关闭

XAF之自定义登录窗口

1654人阅读 评论(1) 收藏 举报

        当使用Standard Authentication验证类型,默认的登录窗口包含两个编辑框:用户名和密码。而本文讲述怎样自定义登录窗口,窗口包含一个下拉式列表选择company,另一个下拉式列表选择该company的employee,还有一个密码输入框。


自定义登录窗口,有以下两种方法:

a.继承AuthenticationStandardLogonParameters类,添加要在登录窗显示的额外属性。然后,可以用安全系统的LogonParameters属性访问特定的登录参数。然而,验证机制仍只使用用户名和密码。所以,若要对额外属性进行验证,需要继承AuthenticationStandard类并重写Authenticate方法。别忘了在Application Designer中指定自定义的登录参数类:

b.实现一个LogonParameters类(不从AuthenticationStandardLogonParameters类继承),添加额外属性。这种情况下,内置的AuthenticationStandard无法执行验证,所以还必须实现自定义的验证策略:继承AuthenticationBase类。

这里,我们使用第二种方法。

实现Employee和Company类

        由于Employee必须支持安全系统,故需要继承BasicUser类。

using System;
using System.Collections.Generic;
using System.Text;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Xpo;
using DevExpress.Persistent.Base;
using DevExpress.ExpressApp.Utils;
using DevExpress.Data.Filtering;
using System.ComponentModel;

namespace AccessDatabaseFromLogonForm.Module {
    [DefaultClassOptions(), System.ComponentModel.DefaultProperty("UserName")]
	public class Employee : SimpleUser {
		private Company company;

        public Employee(Session session)
            : base(session) {
        }

        [Association("Company-Employees", typeof(Company))]
        public Company Company {
            get { return company; }
			set {
				SetPropertyValue("Company", ref company, value);
			}
        }
    }
}
using System;
using DevExpress.Data.Filtering;
using DevExpress.Xpo;
using DevExpress.ExpressApp;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;
using DevExpress.ExpressApp.Utils;

namespace AccessDatabaseFromLogonForm.Module {
    [DefaultClassOptions()]
    public class Company : BaseObject {

        public Company(Session session)
            : base(session) {
        }

        private string name;
        public string Name {
            get { return name; }
			set {
				SetPropertyValue("Name", ref name, value);
			}
        }

        [Association("Company-Employees", typeof(Employee))]
        public XPCollection Employees {
            get { return GetCollection("Employees"); }
        }
    }
}
实现MyLogonParameters类
//实现ISupportResetLogonParameters接口,不必重启程序实现登录和注销
    //在persistent类中,可以在属性setter中使用SetPropertyValue或OnChanged,但MyLogonParameters不是
    //从BaseObject继承而来,故只能实现INotifyPropertyChanged接口
	[NonPersistent]
	public class MyLogonParameters : INotifyPropertyChanged, ISupportResetLogonParameters {
        private IObjectSpace objectSpace;
        //为避免在登录窗口新建Employee和Company,需要设置AvailableCompanies和AvailableUsers只读
        private ReadOnlyCollection<Company> availableCompanies;
        private XPCollection<Employee> availableUsers;

        private Company company;
        private Employee employee;
        private string password;
        private void OnPropertyChanged(string propertyName) {
            if(PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        //显示的Employee要对于其Company,故为availableUsers添加了一个Criteria
        private void RefreshAvailableUsers() {
            if(availableUsers == null) {
                return;
            }

            availableUsers.Criteria = new BinaryOperator("Company", Company);

            if(employee != null && availableUsers.IndexOf(employee) == -1) {
                Employee = null;
            }
            else {
                OnPropertyChanged("Employee");
            }
        }

        [Browsable(false)]
        public IObjectSpace ObjectSpace {
            get { return objectSpace; }
            set { objectSpace = value; }
        }
        //设置为ReadOnlyCollection,只读集合
        [Browsable(false)]
        public ReadOnlyCollection<Company> AvailableCompanies {
            get {
                if (objectSpace == null) {
                    throw new InvalidOperationException("objectSpace is null");
                }
                if (availableCompanies == null) {
					availableCompanies = new ReadOnlyCollection<Company>(ObjectSpace.GetObjects<Company>(null));
				}
                return availableCompanies;
            }
        }
        [Browsable(false)]
        public XPCollection<Employee> AvailableUsers {
            get {
                if (availableUsers == null) {
					availableUsers = (XPCollection<Employee>)ObjectSpace.GetObjects<Employee>();
                    //设置availableUsers只读,不允许绑定的control增/删数据
                    availableUsers.BindingBehavior = CollectionBindingBehavior.AllowNone;
                    RefreshAvailableUsers();
                }
                return availableUsers;
            }
        }
        //DataSourceProperty表示Company依赖于于属性AvailableCompanies,非常类似于PersistentAlias特性
        //但PersistentAlias是对属性的高级”重命名“,DataSourceProperty是属性和数据绑定的关系
        //ImmediatePostData表示当Company数据变化后,立即刷新UI
        [DataSourceProperty("AvailableCompanies"), ImmediatePostData]
        public Company Company {
            get { return company; }
            set {
                company = value;
                RefreshAvailableUsers();
            }
        }

		[DataSourceProperty("AvailableUsers"), ImmediatePostData]
        public Employee Employee {
            get { return employee; }
            set {
                employee = value;
                OnPropertyChanged("Employee");
            }
        }

        [PasswordPropertyText(true)]
        public string Password {
            get { return password; }
            set { password = value; }
        }

        public void Reset() {
            objectSpace = null;
            availableCompanies = null;
            availableUsers = null;
            company = null;
            employee = null;
            password = null;
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

在Program.cs 文件中创建AvailableUsers 和 AvailableCompanies 的ObjectSpaced,并订阅CreateCustomLogonWindowObjectSpace事件

static void Main() {
//...
AccessDatabaseFromLogonFormWindowsFormsApplication application =
new AccessDatabaseFromLogonFormWindowsFormsApplication();
application.CreateCustomLogonWindowObjectSpace +=
new EventHandler<CreateCustomLogonWindowObjectSpaceEventArgs>(
application_CreateCustomLogonWindowObjectSpace);
//...
}
static void application_CreateCustomLogonWindowObjectSpace(object sender,
CreateCustomLogonWindowObjectSpaceEventArgs e) {
e.ObjectSpace = ((XafApplication)sender).CreateObjectSpace();
((MyLogonParameters)e.LogonParameters).ObjectSpace = e.ObjectSpace;
}

实现MyAuthentication类

       继承AuthenticationBase类,并重写以下方法:

Authenticate

      验证时调用。验证时比对数据库里的信息和logon parameter的值。

ClearSecuredLogonParameters

     清除logon parameters,防止在程序里访问它们,这样就隐藏了安全信息。

GetBusinessClasses

      返回要添加到Application Model 中的bussiness classese。如果不返回LogonParameters,则不会在登录窗口中显示该视图。

AskLogonParametersViaUI

     如果需要显示登录窗口获取用户的logon parameters,则返回true。若从其他地方获取logon parameters,如系统活动文件夹,则返回false。

LogonParameters

      返回代表当前logon parameters的对象。

IsLogoffEnabled

     是否允许“注销”操作。当前仅在ASP.NET可用。

public class MyAuthentication : AuthenticationBase, IAuthenticationStandard {
		private MyLogonParameters logonParameters;
        //创建一个LogonParameters对象
		public MyAuthentication() {
			logonParameters = new MyLogonParameters();
		}
        //清除登录信息
		public override void ClearSecuredLogonParameters() {
			logonParameters.Password = "";
			base.ClearSecuredLogonParameters();
		}
        //验证登录,正确则返回该登录用户
		public override object Authenticate(DevExpress.ExpressApp.IObjectSpace objectSpace) {
			if(logonParameters.Employee == null) {
				throw new ArgumentNullException("User");
			}
            //比对密码
			if(!logonParameters.Employee.ComparePassword(logonParameters.Password))
			{
			    throw new AuthenticationException(logonParameters.Employee.UserName, "Wrong password");
			}
			return objectSpace.GetObject(logonParameters.Employee);
		}
		public override IList<Type> GetBusinessClasses() {
			return new Type[] { typeof(MyLogonParameters) };
		}
		public override bool AskLogonParametersViaUI {
			get {
				return true;
			}
		}
		public override object LogonParameters {
			get { return logonParameters; }
		}

		public override bool IsLogoffEnabled {
			get { return true; }
		}
	}
将自定义的这些类传递给系统

          在Application Designer 中,只能添加内置的AuthenticationStandard策略,所以只能在代码中添加MyAuthentication类。WinForm工程里的Main方法中添加:

AccessDatabaseFromLogonFormWindowsFormsApplication application =
new AccessDatabaseFromLogonFormWindowsFormsApplication();
application.Security = new SecuritySimple<Employee>(new MyAuthentication());



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:193367次
    • 积分:3077
    • 等级:
    • 排名:第11241名
    • 原创:106篇
    • 转载:40篇
    • 译文:5篇
    • 评论:34条
    文章分类
    最新评论