创建一个带身份验证与用户授权的XAF (Blazor类型),需要安装的包与各项配置
本文描述:从一个不安全的基本Blazor类型的XAF解决方案,转变成一个安全的XAF解决方案(带身份验证与用户授权),必须的包与配置。
1、创建一个基础XAF,包括的内容,参考: 新建一个 面向目标 net5 的基础 XAF 项目(Blazor型,不带安全的认证与授权) 。
2、创建一个带安全的XAF,比较两者:包与配置的差异,以便学习如何配置 “身份认证与用户授权 ”。
创建面向NetCore的 WinForm 型 XAF方案,使用 XPO 数据存储框架,身份认证Authentication,有三种选择:标准Standard(登录用户+密码)、标准Standard + OAuth2、标准Standard + AD活动目录、标准Standard + OAuth2 + AD活动目录。
经测试,加入“AD活动目录”验证后,“标准Standard”验证 不能使用了。
1) 三个项目都依赖 :DevExpress.ExpressApp.Security.Xpo 包 ,间接依赖:DevExpress.ExpressApp.Security
2)在通用模块项目 XXXX.Module,增加了两个类:ApplicationUser.cs 、 ApplicationUserLoginInfo.cs ,代表用户,但映射的表不变(PermissionPolicyUser)。
Module.cs(分部类 Module.Designer.cs 中) ,InitializeComponent() 方法,增加了:
this.RequiredModuleTypes.Add(typeof(DevExpress.ExpressApp.Security.SecurityModule));
DatabaseUpdate 目录下,Updater.cs 文件增加了 初始化两个用户User(Admin、User ),两个角色Role (Default、Administrators) 。修改 Using 引用。
3)平台相关项目 XXXX.Module.Blazor,引用了 :DevExpress.ExpressApp.Security.Xpo 包。
4) 主体项目的相关变化:
A、BlazorApplication.cs 的分部类 BlazorApplication.Designer.cs
增加属性 : private DevExpress.ExpressApp.Security.SecurityModule securityModule1;
在 InitializeComponent() 方法中增加:
this.securityModule1 = new DevExpress.ExpressApp.Security.SecurityModule();
this.Modules.Add(this.securityModule1);
B、Startup.cs 中是主要配置修改 ConfigureServices(IServiceCollection services)
增加: using DevExpress.ExpressApp.Security;
using DevExpress.Persistent.BaseImpl.PermissionPolicy;
services.AddXafSecurity(options => {
options.RoleType = typeof(PermissionPolicyRole);
options.UserType = typeof(DXBlazor.Module.BusinessObjects.ApplicationUser);
options.UserLoginInfoType = typeof(DXBlazor.Module.BusinessObjects.ApplicationUserLoginInfo);
options.Events.OnSecurityStrategyCreated = securityStrategy =>
((SecurityStrategy)securityStrategy).RegisterXPOAdapterProviders();
options.SupportNavigationPermissionsForTypes = false;
})
.AddAuthenticationStandard(options => {options.IsSupportChangePassword = true; });
.AddExternalAuthentication<HttpContextPrincipalProvider>() ---- 外部验证需要配置参数。
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options => {options.LoginPath = "/LoginPage"; });
C、如果选择AD 活动目录,
AddXafSecurity()后 增加:
.AddAuthenticationActiveDirectory(o => {
o.CreateUserAutomatically = true; })
增加 :services.Configure<IISServerOptions>(options => {
options.AuthenticationDisplayName = "Windows"; });
D、 如果选择 标准Standard + OAuth2, 外部验证需要下列配置参数,另外还需要配置: OAuth2 Identity Providers
.AddExternalAuthentication<HttpContextPrincipalProvider>(options => {
options.Events.OnAuthenticated = (externalAuthenticationContext) => {
return;
if(externalAuthenticationContext.AuthenticatedUser == null &&
externalAuthenticationContext.Principal.Identity.AuthenticationType != SecurityDefaults.PasswordAuthentication &&
externalAuthenticationContext.Principal.Identity.AuthenticationType != SecurityDefaults.WindowsAuthentication && !(externalAuthenticationContext.Principal is WindowsPrincipal)) {
const bool autoCreateUser = true;
IObjectSpace objectSpace = externalAuthenticationContext.LogonObjectSpace;
ClaimsPrincipal externalUser = (ClaimsPrincipal)externalAuthenticationContext.Principal;
var userIdClaim = externalUser.FindFirst("sub") ?? externalUser.FindFirst(ClaimTypes.NameIdentifier) ?? throw new InvalidOperationException("Unknown user id");
string providerUserId = userIdClaim.Value;
var userLoginInfo = FindUserLoginInfo(externalUser.Identity.AuthenticationType, providerUserId);
if(userLoginInfo != null || autoCreateUser) {
externalAuthenticationContext.AuthenticatedUser = userLoginInfo?.User ?? CreateApplicationUser(externalUser.Identity.Name, providerUserId);
}
object CreateApplicationUser(string userName, string providerUserId) {
if(objectSpace.FirstOrDefault<DXStdOAuth2.Module.BusinessObjects.ApplicationUser>(user => user.UserName == userName) != null) {
throw new ArgumentException($"The login with '{userName}' name was already registered within the system");
}
var user = objectSpace.CreateObject<DXStdOAuth2.Module.BusinessObjects.ApplicationUser>();
user.UserName = userName;
user.SetPassword(Guid.NewGuid().ToString());
user.Roles.Add(objectSpace.FirstOrDefault<PermissionPolicyRole>(role => role.Name == "Default"));
((ISecurityUserWithLoginInfo)user).CreateUserLoginInfo(externalUser.Identity.AuthenticationType, providerUserId);
objectSpace.CommitChanges();
return user;
}
ISecurityUserLoginInfo FindUserLoginInfo(string loginProviderName, string providerUserId) {
return objectSpace.FirstOrDefault<DXStdOAuth2.Module.BusinessObjects.ApplicationUserLoginInfo>(userLoginInfo =>
userLoginInfo.LoginProviderName == loginProviderName &&
userLoginInfo.ProviderUserKey == providerUserId);
}
}
};
});