ASP.NET Boilerplate:四眼原理的最佳解决方案是什么

Hoa*_*ran 1 aspnetboilerplate

我想为ASP.NET Boilerplate框架添加4眼原则.这意味着在应用于系统之前,角色,用户等的每个更改都需要(由另一个管理员)批准.我搜索了一段时间但没有回答.那么这个流程的最佳解决方案是什么?

我可以使用Abp表(dbo.AbpUser_Temp等)创建相同的表,并且所有更改都将存储在这些表中吗?有没有更好的解决方案?

示例:在应用程序中,Admin1创建了一个名为User1的用户.但是,在Admin2批准之前,此用户无法登录该应用程序.

aar*_*ron 8

简单的工作流程

示例:在应用程序中,Admin1创建了一个名为User1的用户.但是,在Admin2批准之前,此用户无法登录该应用程序.

像这样的简单工作流可以通过属性和方法适当地处理:

public class User : AbpUser<User>
{
    public bool IsApproved { get; set; }

    public void Approve(User approver)
    {
        if (approver.Id != CreatorUserId)
        {
            IsApproved = true;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

复杂的工作流程

像"每次更改"这样的复杂工作流程可以执行此操作而不是_Temp表格:

public abstract class ChangeBase : Entity<long>, IExtendableObject
{
    public string EntityTypeAssemblyQualifiedName { get; set; }

    public string EntityIdJsonString { get; set; }

    public long ProposerUserId { get; set; }

    public long? ApproverUserId { get; set; }

    public string ExtensionData { get; set; }
}

public class Change : ChangeBase
{
    [NotMapped]
    public Type EntityType => Type.GetType(EntityTypeAssemblyQualifiedName);

    [NotMapped]
    public object EntityId => JsonConvert.DeserializeObject(EntityIdJsonString, EntityHelper.GetPrimaryKeyType(EntityType));

    [NotMapped]
    public bool IsApproved => ApproverUserId.HasValue && ApproverUserId != ProposerUserId;

    [NotMapped]
    public IDictionary<string, string> ChangedPropertyValuePairs => JObject.Parse(ExtensionData).ToObject<Dictionary<string, string>>();

    public Change(EntityIdentifier changedEntityIdentifier, long proposerUserId, IDictionary<string, string> changedPropertyValuePairs)
    {
        EntityTypeAssemblyQualifiedName = changedEntityIdentifier.Type.AssemblyQualifiedName;
        EntityIdJsonString = changedEntityIdentifier.Id.ToJsonString();
        ProposerUserId = proposerUserId;
        ExtensionData = JObject.FromObject(changedPropertyValuePairs).ToString(Formatting.None);
    }

    public bool Approve(long approverUserId)
    {
        if (approverUserId != ProposerUserId)
        {
            ApproverUserId = approverUserId;
            return true;
        }

        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

public class UserAppService // ...
{
    private readonly IRepository<Change, long> _changeRepository;

    public UserAppService(
        IRepository<User, long> repository,
        IRepository<Change, long> changeRepository) // : base(repository)
    {
        _changeRepository = changeRepository;
    }

    public void ChangeUserName(long userId, string newUserName)
    {
        // Validation, etc.

        var changedPropertyValuePairs = new Dictionary<string, string> {
            { nameof(User.UserName), newUserName }
        };

        var change = new Change(
            new EntityIdentifier(typeof(User), userId),
            AbpSession.GetUserId(),
            changedPropertyValuePairs
            );

        _changeRepository.Insert(change);
    }

    public void ApproveChange(long changeId)
    {
        // Validation, etc.

        var change = _changeRepository.Get(changeId);

        if (change.EntityType == typeof(User) && change.Approve(AbpSession.GetUserId()))
        {
            var user = Repository.Get((long)change.EntityId);
            var changedPropertyValuePairs = change.ChangedPropertyValuePairs;

            foreach (var changedProperty in changedPropertyValuePairs.Keys)
            {
                switch (changedProperty)
                {
                    case nameof(User.UserName):
                        user.UserName = changedPropertyValuePairs[changedProperty];
                        break;
                    // ...
                    default:
                        break;
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)