EPR类企业管理系统

在我们现有系统基础上或全新开发,提供定制服务
为您的企业高效快速实施ERP,WMS,MES,CRM管理系统
全面管控物料仓库、销售业务、采购业务、仓库业务
生产过程、质量检验、组织架构、业务报表


定制
QQ:460-3528

开发
QQ群:3360-90194

源码
微信:136-3650-3721

如何:使用自定义登录参数和身份验证

启用AuthenticationStandard身份验证后,登录表单将显示“用户名”编辑器。本主题说明如何自定义登录表单编辑器。例如,显示“公司”和“雇员”查找编辑器,而不是“用户名”。

注意

移动应用程序不支持登录表单上的“查找属性编辑器”。但是,您可以使用其他支持的属性编辑器(例如,字符串)来实现自定义登录参数和身份验证。

CustomLogonParameters

登录表单显示AuthenticationStandardLogonParameters详细信息视图。该AuthenticationStandardLogonParameters对象具有 用户名密码字符串属性。

若要使用自定义登录参数,请实现自定义登录参数类。此类的属性显示在登录表单上,并且可以使用SecuritySystem.LogonParameters属性进行访问。要指定您的应用程序如何对用户进行身份验证,请继承AuthenticationBase类并实现自定义身份验证策略类。以下各节描述了如何实现此目的:

注意

或者,您可以使用ICustomObjectSerialize主题中的方法-继承AuthenticationStandardLogonParameters类并实现其他属性。然后,您可以使用LogonParameters属性访问指定的登录参数。在这种情况下,仍使用指定的用户名密码执行身份验证过程。要将添加的属性包括在身份验证过程中,请继承AuthenticationStandard类并重写Authenticate方法。您还应该使用以下命令在“应用程序设计器”中指定自定义登录参数类:AuthenticationStandard.LogonParametersType属性。

实施员工和公司类别

员工类应该从继承PermissionPolicyUser类,以支持保障体系。添加公司属性,并使其成为“公司-雇员”关联的一部分。

using System.ComponentModel;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl.PermissionPolicy;
using DevExpress.Xpo;
// ...
[DefaultClassOptions, DefaultProperty(nameof(UserName))]
public class Employee : PermissionPolicyUser{
    public Employee(Session session) : base(session) {}
    private Company company;
    [Association("Company-Employees")]
    public Company Company {
        get { return company; }
        set { SetPropertyValue(nameof(Company), ref company, value);}
    }
}

公司类应该有“公司员工”联想的第二部分。

using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Xpo;
// ...
[DefaultClassOptions]
public class Company : BaseObject {
    public Company(Session session) : base(session) {}
    private string name;
    public string Name {
        get { return name; }
        set { SetPropertyValue(nameof(Name), ref name, value); }
    }
    [Association("Company-Employees")]
    public XPCollection<Employee> Employees {
        get { return GetCollection<Employee>(nameof(Employees)); }
    }
}

接下来,为模块项目调用模型编辑器,展开“视图” | “视图”。CustomLogonParametersExample.Module.BusinessObjects节点,然后找到EmployeeCompany的查找列表视图。为了防止在这些视图中创建新对象,请将两个视图的IModelView.AllowNew属性都设置为false

ModelEditor_AllowNew

实现CustomLogonParameters类

以下代码段说明了CustomLogonParameters类的实现:

using System;
using System.ComponentModel;
using System.Runtime.Serialization;
using CustomLogonParametersExample.Module.BusinessObjects;
using DevExpress.ExpressApp.DC;
using DevExpress.Persistent.Base;

namespace CustomLogonParametersExample.Module {
    [DomainComponent, Serializable]
    [System.ComponentModel.DisplayName("Log In")]
    public class CustomLogonParameters : INotifyPropertyChanged, ISerializable {
        private Company company;
        private Employee employee;
        private string password;

        [ImmediatePostData]
        public Company Company {
            get { return company; }
            set {
                if (value == company) return;
                company = value;
                Employee = null;
                OnPropertyChanged(nameof(Company));
            }
        }
        [DataSourceProperty("Company.Employees"), ImmediatePostData]
        public Employee Employee {
            get { return employee; }
            set {
                if (Company == null) return;
                employee = value;
                if (employee != null) {
                    UserName = employee.UserName;
                }
                OnPropertyChanged(nameof(Employee));
            }
        }
        [Browsable(false)]
        public String UserName { get; set; }
        [PasswordPropertyText(true)]
        public string Password {
            get { return password; }
            set {
                if (password == value) return;
                password = value;
            }
        }
        public CustomLogonParameters() { }
        // ISerializable 
        public CustomLogonParameters(SerializationInfo info, StreamingContext context) {
            if (info.MemberCount > 0) {
                UserName = info.GetString("UserName");
                Password = info.GetString("Password");
            }
        }
        private void OnPropertyChanged(string propertyName) {
            if (PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        [System.Security.SecurityCritical]
        public void GetObjectData(SerializationInfo info, StreamingContext context) {
            info.AddValue("UserName", UserName);
            info.AddValue("Password", Password);
        }
    }
}

员工公司密码的属性是可见的,可以在登录表单进行编辑。该DataSourcePropertyAttribute指定查找属性编辑器的下拉列表中的内容。若要仅显示与所选公司相关的员工,请过滤下拉列表的集合,并在“公司”属性每次更改时刷新它。

注意

在“中间层安全性-WCF服务”方案中,需要对登录参数进行序列化。但是,引用属性无法序列化。这就是为什么需要字符串类型的隐藏的UserName属性的原因。

提示

若要访问代码中的自定义登录参数对象,请将静态 SecuritySystem.LogonParameters属性的值强制转换为CustomLogonParameters类型,或者处理XafApplication.LoggedOn事件,并使用LogonEventArgs.LogonParameters参数值。

允许在登录窗口中访问公司和员工类型

公司雇员类型添加到WinForms和ASP.NET应用程序中的SecurityStrategy.AnonymousAllowedTypes集合中。

  • 在WinForms应用程序项目中,打开WinApplication.csWinApplication.vb)文件,并将以下代码添加到WinApplication后代的构造函数中:

    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.Security;
    using DevExpress.ExpressApp.Win;
    // ...
    public partial class CustomLogonParametersExampleWindowsFormsApplication : WinApplication {
        // ...
        public CustomLogonParametersExampleWindowsFormsApplication() {
            // ...
            ((SecurityStrategy)Security).AnonymousAllowedTypes.Add(typeof(Company));
            ((SecurityStrategy)Security).AnonymousAllowedTypes.Add(typeof(Employee));
        }
        // ...
    }
    
  • 在ASP.NET应用程序项目中,打开WebApplication.csWebApplication.vb)文件,然后将以下代码添加到WebApplication后代的构造函数中:

    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.Security;
    using DevExpress.ExpressApp.Web;
    // ...
    public partial class CustomLogonParametersExampleAspNetApplication : WebApplication {
        // ...
        public CustomLogonParametersExampleAspNetApplication() {
            // ...
            ((SecurityStrategy)Security).AnonymousAllowedTypes.Add(typeof(Company));
            ((SecurityStrategy)Security).AnonymousAllowedTypes.Add(typeof(Employee));
        }
        // ...
    }
    

为登录窗口提供对象空间

创建一个对象空间以在XafApplication.CreateCustomLogonWindowObjectSpace事件中显示EmployeeCompany属性。将CreateCustomLogonWindowObjectSpaceEventArgs.ObjectSpace参数分配给使用XafApplication.CreateObjectSpace方法创建的新对象空间,然后将此新对象空间添加到NonPersistentObjectSpace.AdditionalObjectSpaces列表中,如下所示。

  • 在WinForms应用程序中

    在WinForms应用程序项目中 打开Program.csProgram.vb)文件,并在您的Program.Main方法中调用XafApplication.Setup方法之前,订阅CreateCustomLogonWindowObjectSpace事件。

    using CustomLogonParametersExample.Module;
    using CustomLogonParametersExample.Module.BusinessObjects;
    using DevExpress.ExpressApp;
    // ...
    static class Program {
        // ...
        static void Main() {
            // ...
            winApplication.CreateCustomLogonWindowObjectSpace  = 
            application_CreateCustomLogonWindowObjectSpace;
            winApplication.Setup();
            // ...
        }
        private static void application_CreateCustomLogonWindowObjectSpace(object sender, 
        CreateCustomLogonWindowObjectSpaceEventArgs e) {
            e.ObjectSpace = ((XafApplication)sender).CreateObjectSpace(typeof(CustomLogonParameters));
            if (e.ObjectSpace is NonPersistentObjectSpace) {
                IObjectSpace objectSpaceCompany = ((XafApplication)sender).CreateObjectSpace(typeof(Company));
                ((NonPersistentObjectSpace)e.ObjectSpace).AdditionalObjectSpaces.Add(objectSpaceCompany);
            }
        }
    }
    

    在WinForms应用程序中,可以在WinApplication.CreateDefaultObjectSpaceProvider方法中自定义对象空间提供程序。若要为非持久类型创建对象空间提供程序,请在WinForms应用程序项目中打开WinApplication.csWinApplication.vb)文件,并重写CreateDefaultObjectSpaceProvider方法,如下所示。

    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.Win;
    using DevExpress.ExpressApp.Xpo;
    // ...
    public partial class CustomLogonParametersExampleWindowsFormsApplication : WinApplication {
        // ...
        protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) {
            args.ObjectSpaceProviders.Add(new XPObjectSpaceProvider(args.ConnectionString, args.Connection, false));
            args.ObjectSpaceProviders.Add(new NonPersistentObjectSpaceProvider(TypesInfo, null));
        }
    }
    
  • 在ASP.NET应用程序中

    打开的Global.asax.csGlobal.asax.vb在ASP.NET应用程序项目)的文件,并订阅CreateCustomLogonWindowObjectSpace事件之前XafApplication.Setup方法中调用的Global.Session_Start方法。

    using CustomLogonParametersExample.Module;
    using CustomLogonParametersExample.Module.BusinessObjects;
    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.Web;
    // ...
    public class Global : System.Web.HttpApplication {
        // ...
        protected void Session_Start(Object sender, EventArgs e) {
            // ...
            WebApplication.Instance.CreateCustomLogonWindowObjectSpace  = 
            application_CreateCustomLogonWindowObjectSpace;
            WebApplication.Instance.Setup();
            // ...
        }
        private static void application_CreateCustomLogonWindowObjectSpace(object sender, 
        CreateCustomLogonWindowObjectSpaceEventArgs e) {
            e.ObjectSpace = ((XafApplication)sender).CreateObjectSpace(typeof(CustomLogonParameters));
            if (e.ObjectSpace is NonPersistentObjectSpace) {
                IObjectSpace objectSpaceCompany = ((XafApplication)sender).CreateObjectSpace(typeof(Company));
                ((NonPersistentObjectSpace)e.ObjectSpace).AdditionalObjectSpaces.Add(objectSpaceCompany);
            }
        }
    }
    

    在ASP.NET应用程序中,可以使用静态NonPersistentTypeInfoSource类在WebApplication.CreateDefaultObjectSpaceProvider方法中自定义对象空间提供程序。若要为非持久类型创建对象空间提供程序,请在ASP.NET应用程序项目中打开WebApplication.cs(WebApplication.vb)文件,声明新的静态NonPersistentTypeInfoSource对象,并重写CreateDefaultObjectSpaceProvider方法,如下所示。

    using System;
    using System.Collections.Generic;
    using CustomLogonParametersExample.Module;
    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.DC;
    using DevExpress.ExpressApp.Xpo;
    using DevExpress.ExpressApp.Web;
    // ...
    public partial class CustomLogonParametersExampleAspNetApplication : WebApplication {
        private static NonPersistentTypeInfoSource nonPersistentTypeInfoSource;
        // ...
        protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) {
            args.ObjectSpaceProvider = 
            new XPObjectSpaceProvider(GetDataStoreProvider(args.ConnectionString, args.Connection), true);
            if (nonPersistentTypeInfoSource == null) {
                nonPersistentTypeInfoSource = new NonPersistentTypeInfoSource(TypesInfo, new List<Type>() 
                   { typeof(CustomLogonParameters) });
            }
            args.ObjectSpaceProviders.Add(new NonPersistentObjectSpaceProvider(TypesInfo, 
            nonPersistentTypeInfoSource));
        }
    }
    

实现CustomAuthentication类

要实现自定义身份验证,请继承AuthenticationBase类。

using System;
using System.Collections.Generic;
using CustomLogonParametersExample.Module.BusinessObjects;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Security;

namespace CustomLogonParametersExample.Module {
    public class CustomAuthentication : AuthenticationBase, IAuthenticationStandard {
        private CustomLogonParameters customLogonParameters;
        public CustomAuthentication() {
            customLogonParameters = new CustomLogonParameters();
        }
        public override void Logoff() {
            base.Logoff();
            customLogonParameters = new CustomLogonParameters();
        }
        public override void ClearSecuredLogonParameters() {
            customLogonParameters.Password = "";
            base.ClearSecuredLogonParameters();
        }
        public override object Authenticate(IObjectSpace objectSpace) {

            Employee employee = objectSpace.FindObject<Employee>(
                new BinaryOperator("UserName", customLogonParameters.UserName));

            if (employee == null)
                throw new ArgumentNullException("Employee");

            if (!employee.ComparePassword(customLogonParameters.Password))
                throw new AuthenticationException(
                    employee.UserName, "Password mismatch.");

            return employee;
        }

        public override void SetLogonParameters(object logonParameters) {
            this.customLogonParameters = (CustomLogonParameters)logonParameters;
        }

        public override IList<Type> GetBusinessClasses() {
            return new Type[] { typeof(CustomLogonParameters) };
        }
        public override bool AskLogonParametersViaUI {
            get { return true; }
        }
        public override object LogonParameters {
            get { return customLogonParameters; }
        }
        public override bool IsLogoffEnabled {
            get { return true; }
        }
    }
}

请参阅基类描述,以获取有关在上面的代码中覆盖的方法和属性的信息。

注意

客户端服务器安全配置中,还需要您执行以下操作:

将自定义类传递给安全系统

调用应用程序设计器。将SecurityStrategyComplex组件从工具箱拖到设计器的安全窗格中。然后,将您实现的CustomAuthentication组件放在与平台无关的模块内的同一窗格中。

CustomLogonParameters_StrategyAndAuthentication

关注SecurityStrategyComplex组件。在“属性”窗口中,将SecurityStrategy.UserType设置为Employee

CustomLogonParameters_UserAndRoleTypes

创建演示数据(公司,员工和安全角色)

重写ModuleUpdater.UpdateDatabaseAfterUpdateSchema方法。在此方法中创建公司,员工和角色。

using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.Security.Strategy;
// ...
public class Updater : ModuleUpdater {
    public Updater(IObjectSpace objectSpace, Version currentDBVersion) : base(objectSpace, currentDBVersion) { }
    public override void UpdateDatabaseAfterUpdateSchema() {
        base.UpdateDatabaseAfterUpdateSchema();
        PermissionPolicyRole administrativeRole = ObjectSpace.FindObject<PermissionPolicyRole>(
            new BinaryOperator("Name", SecurityStrategy.AdministratorRoleName));
        if (administrativeRole == null) {
            administrativeRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
            administrativeRole.Name = SecurityStrategy.AdministratorRoleName;
            administrativeRole.IsAdministrative = true;
        }
        const string adminName = "Administrator";
        Employee administratorUser = ObjectSpace.FindObject<Employee>(
            new BinaryOperator("UserName", adminName));
        if (administratorUser == null) {
            administratorUser = ObjectSpace.CreateObject<Employee>();
            administratorUser.UserName = adminName;
            administratorUser.IsActive = true;
            administratorUser.SetPassword("");
            administratorUser.Roles.Add(administrativeRole);
        }
        PermissionPolicyRole userRole = ObjectSpace.FindObject<PermissionPolicyRole>(
            new BinaryOperator("Name", "User"));
        if (userRole == null) {
            userRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
            userRole.Name = "User";
            userRole.AddTypePermission<Employee>(
                SecurityOperations.ReadOnlyAccess, SecurityPermissionState.Allow);
            userRole.AddTypePermission<Company>(
                SecurityOperations.ReadOnlyAccess, SecurityPermissionState.Allow);
        }
        if (ObjectSpace.FindObject<Company>(null) == null) {
            Company company1 = ObjectSpace.CreateObject<Company>();
            company1.Name = "Company 1";
            company1.Employees.Add(administratorUser);
            Employee user1 = ObjectSpace.CreateObject<Employee>();
            user1.UserName = "Sam";
            user1.SetPassword("");
            user1.Roles.Add(userRole);
            Employee user2 = ObjectSpace.CreateObject<Employee>();
            user2.UserName = "John";
            user2.SetPassword("");
            user2.Roles.Add(userRole);
            Company company2 = ObjectSpace.CreateObject<Company>();
            company2.Name = "Company 2";
            company2.Employees.Add(user1);
            company2.Employees.Add(user2);
        }
        ObjectSpace.CommitChanges();
    }
}

现在,您可以运行该应用程序以在登录表单上查看自定义登录参数。

相关文章

转载保留此链接,注明出处