首页 > 代码库 > XAF-如何实现自定义权限系统用户对象

XAF-如何实现自定义权限系统用户对象

本示例使用XPO.

新建一个XAF项目.填加两个类进来:

 
[DefaultClassOptions]
public class Employee : Person {
    public Employee(Session session)
        : base(session) { }
    [Association("Employee-Task")]
    public XPCollection<EmployeeTask> OwnTasks {
        get { return GetCollection<EmployeeTask>("OwnTasks"); }
    }
}
[DefaultClassOptions, ImageName("BO_Task")]
public class EmployeeTask : Task {
    public EmployeeTask(Session session)
        : base(session) { }
    private Employee owner;
    [Association("Employee-Task")]
    public Employee Owner {
        get { return owner; }
        set { SetPropertyValue("Owner", ref owner, value); }
    }
}

 


技术分享 实现接口: ISecurityUser

 

填加引用: DevExpress.ExpressApp.Security.v16.2.dll 程序集 

using DevExpress.ExpressApp.Security;
using DevExpress.Persistent.Validation;
// ... 
public class Employee : Person, ISecurityUser {
    // ... 
    #region ISecurityUser Members
    private bool isActive = true;
    public bool IsActive {
        get { return isActive; }
        set { SetPropertyValue("IsActive", ref isActive, value); }
    }
    private string userName = String.Empty;
    [RuleRequiredField("EmployeeUserNameRequired", DefaultContexts.Save)]
    [RuleUniqueValue("EmployeeUserNameIsUnique", DefaultContexts.Save, 
        "The login with the entered user name was already registered within the system.")]
    public string UserName {
        get { return userName; }
        set { SetPropertyValue("UserName", ref userName, value); }
    }
    #endregion
}

 

技术分享 实现 IAuthenticationStandardUser 接口

using System.ComponentModel;
using DevExpress.Persistent.Base.Security;
// ... 
public class Employee : Person, ISecurityUser, IAuthenticationStandardUser {
    // ... 
    #region IAuthenticationStandardUser Members
    private bool changePasswordOnFirstLogon;
    public bool ChangePasswordOnFirstLogon {
        get { return changePasswordOnFirstLogon; }
        set { 
            SetPropertyValue("ChangePasswordOnFirstLogon", ref changePasswordOnFirstLogon, value);
        }
    }
    private string storedPassword;
    [Browsable(false), Size(SizeAttribute.Unlimited), Persistent, SecurityBrowsable]
    protected string StoredPassword {
        get { return storedPassword; }
        set { storedPassword = value; }
    }
    public bool ComparePassword(string password) {
        return PasswordCryptographer.VerifyHashedPasswordDelegate(this.storedPassword, password);
    }
    public void SetPassword(string password) {
        this.storedPassword = PasswordCryptographer.HashPasswordDelegate(password);
        OnChanged("StoredPassword");
    }
    #endregion
}

如果不想支持AuthenticationStandard验证方式,则不需要实现这个接口.

 

技术分享 支持IAuthenticationActiveDirectoryUser 接口,为活动目录验证方式提供支持

 
using DevExpress.Persistent.Base.Security;
// ... 
public class Employee : Person, ISecurityUser, 
    IAuthenticationStandardUser, IAuthenticationActiveDirectoryUser {
    // ... 
}

如果不想支持 AuthenticationActiveDirectory 验证方式则不需要实现此步骤.

 

技术分享 支持 ISecurityUserWithRoles 接口.即,让用户支持角色

[DefaultClassOptions]
public class Employee : Person, ISecurityUser,
    IAuthenticationStandardUser, IAuthenticationActiveDirectoryUser,
    ISecurityUserWithRoles {
    // ... 
    #region ISecurityUserWithRoles Members
    IList<ISecurityRole> ISecurityUserWithRoles.Roles {
        get {
            IList<ISecurityRole> result = new List<ISecurityRole>();
            foreach (EmployeeRole role in EmployeeRoles) {
                result.Add(role);
            }
            return result;
        }
    }
    #endregion
    [Association("Employees-EmployeeRoles")]
    [RuleRequiredField("EmployeeRoleIsRequired", DefaultContexts.Save,
        TargetCriteria = "IsActive",
        CustomMessageTemplate = "An active employee must have at least one role assigned")]
    public XPCollection<EmployeeRole> EmployeeRoles {
        get {
            return GetCollection<EmployeeRole>("EmployeeRoles");
        }
    }
}

定义了一个角色,是继承自系统内置的:

using DevExpress.Persistent.BaseImpl.PermissionPolicy;
// ... 
[ImageName("BO_Role")]
public class EmployeeRole : PermissionPolicyRoleBase, IPermissionPolicyRoleWithUsers {
    public EmployeeRole(Session session)
        : base(session) {
    }
    [Association("Employees-EmployeeRoles")]
    public XPCollection<Employee> Employees {
        get {
            return GetCollection<Employee>("Employees");
        }
    }
    IEnumerable<IPermissionPolicyUser> IPermissionPolicyRoleWithUsers.Users {
        get { return Employees.OfType<IPermissionPolicyUser>(); }
    } 
}

 

技术分享 支持 IPermissionPolicyUser 接口,为实现每个用户提供权限数据

 
using DevExpress.ExpressApp.Utils;
// ... 
[DefaultClassOptions]
public class Employee : Person, ISecurityUser,
    IAuthenticationStandardUser, IAuthenticationActiveDirectoryUser,
    IPermissionPolicyUser {
    // ... 
    #region IPermissionPolicyUser Members
    IEnumerable<IPermissionPolicyRole> IPermissionPolicyUser.Roles {
        get { return EmployeeRoles.OfType<IPermissionPolicyRole>(); }
    }
    #endregion
}

其实这个接口还是挺有用的,上面的代码是从角色中读取权限的数据.

 

技术分享 支持 ICanInitialize 接口 

 

ICanInitialize.Initialize 在 AuthenticationActiveDirectory 验证方式并且设置了 AuthenticationActiveDirectory.CreateUserAutomatically为true时.如果你不需要支持这个自动创建,可以跳过这里.

 

using DevExpress.ExpressApp;
using DevExpress.Data.Filtering;
// ... 
[DefaultClassOptions]
public class Employee : Person, ISecurityUser,
    IAuthenticationStandardUser, IAuthenticationActiveDirectoryUser,
    IPermissionPolicyUser, ICanInitialize {
    // ... 
    #region ICanInitialize Members
    void ICanInitialize.Initialize(IObjectSpace objectSpace, SecurityStrategyComplex security) {
        EmployeeRole newUserRole = (EmployeeRole)objectSpace.FindObject<EmployeeRole>(
            new BinaryOperator("Name", security.NewUserRoleName));
        if (newUserRole == null) {
            newUserRole = objectSpace.CreateObject<EmployeeRole>();
            newUserRole.Name = security.NewUserRoleName;
            newUserRole.IsAdministrative = true;
            newUserRole.Employees.Add(this);
        }
    }
    #endregion
}

技术分享 应用创建的自定义类

 

 如图所示,在属性栏中设置自定义的类.

技术分享

技术分享 创建管理员账号

 如果你决定使用活动目录验证方式,需要跳过这里.
在module项目的databaseUpdate文件夹中,找到Updater.cs. 重写 ModuleUpdater.UpdateDatabaseAfterUpdateSchema 方法.
 
using DevExpress.ExpressApp.Security.Strategy;
// ... 
public override void UpdateDatabaseAfterUpdateSchema() {
    base.UpdateDatabaseAfterUpdateSchema();
    EmployeeRole adminEmployeeRole = ObjectSpace.FindObject<EmployeeRole>(
        new BinaryOperator("Name", SecurityStrategy.AdministratorRoleName));
    if (adminEmployeeRole == null) {
        adminEmployeeRole = ObjectSpace.CreateObject<EmployeeRole>();
        adminEmployeeRole.Name = SecurityStrategy.AdministratorRoleName;
        adminEmployeeRole.IsAdministrative = true;
        adminEmployeeRole.Save();
    }
    Employee adminEmployee = ObjectSpace.FindObject<Employee>(
        new BinaryOperator("UserName", "Administrator"));
    if (adminEmployee == null) {
        adminEmployee = ObjectSpace.CreateObject<Employee>();
        adminEmployee.UserName = "Administrator";
        adminEmployee.SetPassword("");
        adminEmployee.EmployeeRoles.Add(adminEmployeeRole);
    }
    ObjectSpace.CommitChanges();
}

就是说,在数据库结构创建(或更新)完成后,执行上面的代码.

 

技术分享 运行

 win:
技术分享

 

 

技术分享 只显示当前用户的的"任务"

应用 ListViewFilterAttribute 特性到EmployeeTask 类,定义一个列表过滤.
CurrentUserId会取得当前用户的id
[ListViewFilter("All Tasks", "")]
[ListViewFilter("My Tasks", "[Owner.Oid] = CurrentUserId()")]
public class EmployeeTask : Task {
    // ... 
}

结果如下.

技术分享
 
如果你只是想为用户加几个属性,则不需要上面这么麻烦
直接继承自PermissionPolicyUser即可,然后加属性.当然,不要忘记
技术分享
这一步的应用类就好了.
 

XAF-如何实现自定义权限系统用户对象