Example E4037
Visible to All Users

XAF Blazor UI: How to extend the logon form - register a new user, restore a password

XAF Blazor UI: How to extend the logon form - register a new user, restore a password

NOTE:
An alternative solution exists:

How to: Use Google, Facebook and Microsoft accounts in ASP.NET XAF applications (OAuth2 authentication demo).

Instead of a custom-tailored implementation, we recommend that you delegate these routine tasks to OAuth2 providers. Microsoft 365 or Google GSuite services enable user and document management that's familiar to anyone who works with business apps. Your XAF application can easily integrate these OAuth2 providers into the logon form. You only need to add some boilerplate code.

Implementation Details

This example contains a reusable Security.Extensions module that enables the following functionality:

image

The module includes the following notable building blocks:

  • Application Model settings (Model.DesignedDiffs.xafml) that place custom Actions next to the logon form input fields. See How to: Include an Action to a Detail View Layout.
  • Non-persistent data models for parameter screens (LogonActionParameters.cs)
  • A View Controller (ManageUsersOnLogonController.cs) for the logon Detail View. The controller declares custom Actions and their behavior. See the XafApplication.CreateCustomLogonWindowControllers event in Module.cs to find controller registration code and other service logic.

Extend the Logon Form in Your Project

In order to use this module in your own project, follow the steps below:

  1. Download the Security.Extensions module project, include it in your XAF solution, and rebuild the solution. See How to Add an Existing Project in MSDN for details.
  2. Add the Security.Extensions.SecurityExtensionsModule to your application. To do this, use any of the techniques described in the following help topic: Ways to Register a Module.
  3. Add the following code to your platform-agnostic module class:
    C#
    static YourPlatformAgnosticModuleName() { SecurityExtensionsModule.CreateSecuritySystemUser = Updater.CreateUser; }
    In the above code sample, Updater.CreateUser is your custom method that matches the following definition:
    C#
    public delegate IAuthenticationStandardUser CreateSecuritySystemUser(IObjectSpace objectSpace, string userName, string email, string password, bool isAdministrator);
  4. Add the following types to the SecurityStrategy.AnonymousAllowedTypes collection:

Files to Review

NOTE: Implementation details do not depend on your ORM tool of choice, so the following two sets of files contain the same code. We added both lists for your convenience - so you can navigate directly to the solution folder that you need.

EF Core:

XPO:

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

NOTE:
An alternative solution exists:

How to: Use Google, Facebook and Microsoft accounts in ASP.NET XAF applications (OAuth2 authentication demo).

Instead of a custom-tailored implementation, we recommend that you delegate these routine tasks to OAuth2 providers. Microsoft 365 or Google GSuite services enable user and document management that's familiar to anyone who works with business apps. Your XAF application can easily integrate these OAuth2 providers into the logon form. You only need to add some boilerplate code.

Implementation Details

This example contains a reusable Security.Extensions module that enables the following functionality:

image

The module includes the following notable building blocks:

  • Application Model settings (Model.DesignedDiffs.xafml) that place custom Actions next to the logon form input fields. See How to: Include an Action to a Detail View Layout.
  • Non-persistent data models for parameter screens (LogonActionParameters.cs)
  • A View Controller (ManageUsersOnLogonController.cs) for the logon Detail View. The controller declares custom Actions and their behavior. See the XafApplication.CreateCustomLogonWindowControllers event in Module.cs to find controller registration code and other service logic.

Extend the Logon Form in Your Project

In order to use this module in your own project, follow the steps below:

  1. Download the Security.Extensions module project, include it in your XAF solution, and rebuild the solution. See How to Add an Existing Project in MSDN for details.
  2. Add the Security.Extensions.SecurityExtensionsModule to your application. To do this, use any of the techniques described in the following help topic: Ways to Register a Module.
  3. Add the following code to your platform-agnostic module class:
    C#
    static YourPlatformAgnosticModuleName() { SecurityExtensionsModule.CreateSecuritySystemUser = Updater.CreateUser; }
    In the above code sample, Updater.CreateUser is your custom method that matches the following definition:
    C#
    public delegate IAuthenticationStandardUser CreateSecuritySystemUser(IObjectSpace objectSpace, string userName, string email, string password, bool isAdministrator);
  4. Add the following types to the SecurityStrategy.AnonymousAllowedTypes collection:

Files to Review

NOTE: Implementation details do not depend on your ORM tool of choice, so the following two sets of files contain the same code. We added both lists for your convenience - so you can navigate directly to the solution folder that you need.

EF Core:

XPO:

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

EFCore/DXApplication1.Module/DatabaseUpdate/Updater.cs
C#
using DevExpress.ExpressApp; using DevExpress.Data.Filtering; using DevExpress.Persistent.Base; using DevExpress.ExpressApp.Updating; using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.SystemModule; using DevExpress.ExpressApp.EF; using DevExpress.Persistent.BaseImpl.EF; using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy; using DXApplication1.Module.BusinessObjects; using Microsoft.Extensions.DependencyInjection; using DevExpress.Persistent.Base.Security; using DevExpress.Persistent.Validation; using System.Security.AccessControl; namespace DXApplication1.Module.DatabaseUpdate; // For more typical usage scenarios, be sure to check out https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Updating.ModuleUpdater public class Updater : ModuleUpdater { public Updater(IObjectSpace objectSpace, Version currentDBVersion) : base(objectSpace, currentDBVersion) { } public static IAuthenticationStandardUser CreateUser(IObjectSpace objectSpace, string userName, string email, string password, bool isAdministrator) { if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(email)) { throw new UserFriendlyException("User Name and Email address are not specified!"); } var userManager = objectSpace.ServiceProvider.GetRequiredService<UserManager>(); if (userManager.FindUserByName<ApplicationUser>(objectSpace, userName) != null) { throw new UserFriendlyException("A user already exists with this name."); } if (objectSpace.FirstOrDefault<ApplicationUser>(user => user.Email == email) != null) { throw new UserFriendlyException("A user already exists with this email."); } var role = isAdministrator ? GetAdminRole(objectSpace) : GetDefaultRole(objectSpace); var result = userManager.CreateUser<ApplicationUser>(objectSpace, userName, password, (user) => { user.Email = email; user.Roles.Add(role); }); if (!result.Succeeded) { throw new UserFriendlyException("Error creating a new user."); } return result.User; } public override void UpdateDatabaseAfterUpdateSchema() { base.UpdateDatabaseAfterUpdateSchema(); // The code below creates users and roles for testing purposes only. // In production code, you can create users and assign roles to them automatically, as described in the following help topic: // https://docs.devexpress.com/eXpressAppFramework/119064/data-security-and-safety/security-system/authentication #if !RELEASE // If a role doesn't exist in the database, create this role var defaultRole = GetDefaultRole(ObjectSpace); var adminRole = GetAdminRole(ObjectSpace); ObjectSpace.CommitChanges(); //This line persists created object(s). string EmptyPassword = ""; var userManager = ObjectSpace.ServiceProvider.GetRequiredService<UserManager>(); if (userManager.FindUserByName<ApplicationUser>(ObjectSpace, "User") == null) { CreateUser(ObjectSpace, "User", "user@example.com", EmptyPassword, isAdministrator: false); } if (userManager.FindUserByName<ApplicationUser>(ObjectSpace, "Admin") == null) { CreateUser(ObjectSpace, "Admin", "admin@example.com", EmptyPassword, isAdministrator: true); } ObjectSpace.CommitChanges(); //This line persists created object(s). #endif } public override void UpdateDatabaseBeforeUpdateSchema() { base.UpdateDatabaseBeforeUpdateSchema(); } private static PermissionPolicyRole GetAdminRole(IObjectSpace objectSpace) { PermissionPolicyRole adminRole = objectSpace.FirstOrDefault<PermissionPolicyRole>(r => r.Name == "Administrators"); if(adminRole == null) { adminRole = objectSpace.CreateObject<PermissionPolicyRole>(); adminRole.Name = "Administrators"; adminRole.IsAdministrative = true; } return adminRole; } private static PermissionPolicyRole GetDefaultRole(IObjectSpace objectSpace) { PermissionPolicyRole defaultRole = objectSpace.FirstOrDefault<PermissionPolicyRole>(role => role.Name == "Default"); if(defaultRole == null) { defaultRole = objectSpace.CreateObject<PermissionPolicyRole>(); defaultRole.Name = "Default"; defaultRole.AddObjectPermissionFromLambda<ApplicationUser>(SecurityOperations.Read, cm => cm.ID == (Guid)CurrentUserIdOperator.CurrentUserId(), SecurityPermissionState.Allow); defaultRole.AddNavigationPermission(@"Application/NavigationItems/Items/Default/Items/MyDetails", SecurityPermissionState.Allow); defaultRole.AddMemberPermissionFromLambda<ApplicationUser>(SecurityOperations.Write, "ChangePasswordOnFirstLogon", cm => cm.ID == (Guid)CurrentUserIdOperator.CurrentUserId(), SecurityPermissionState.Allow); defaultRole.AddMemberPermissionFromLambda<ApplicationUser>(SecurityOperations.Write, "StoredPassword", cm => cm.ID == (Guid)CurrentUserIdOperator.CurrentUserId(), SecurityPermissionState.Allow); defaultRole.AddTypePermissionsRecursively<PermissionPolicyRole>(SecurityOperations.Read, SecurityPermissionState.Deny); defaultRole.AddObjectPermission<ModelDifference>(SecurityOperations.ReadWriteAccess, "UserId = ToStr(CurrentUserId())", SecurityPermissionState.Allow); defaultRole.AddObjectPermission<ModelDifferenceAspect>(SecurityOperations.ReadWriteAccess, "Owner.UserId = ToStr(CurrentUserId())", SecurityPermissionState.Allow); defaultRole.AddTypePermissionsRecursively<ModelDifference>(SecurityOperations.Create, SecurityPermissionState.Allow); defaultRole.AddTypePermissionsRecursively<ModelDifferenceAspect>(SecurityOperations.Create, SecurityPermissionState.Allow); } return defaultRole; } }
EFCore/DXApplication1.Blazor.Server/Startup.cs
C#
using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.ApplicationBuilder; using DevExpress.ExpressApp.Blazor.ApplicationBuilder; using DevExpress.ExpressApp.Blazor.Services; using DevExpress.Persistent.Base; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Components.Server.Circuits; using Microsoft.EntityFrameworkCore; using DXApplication1.Blazor.Server.Services; using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy; namespace DXApplication1.Blazor.Server; public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddSingleton(typeof(Microsoft.AspNetCore.SignalR.HubConnectionHandler<>), typeof(ProxyHubConnectionHandler<>)); services.AddRazorPages(); services.AddServerSideBlazor(); services.AddHttpContextAccessor(); services.AddScoped<CircuitHandler, CircuitHandlerProxy>(); services.AddXaf(Configuration, builder => { builder.UseApplication<DXApplication1BlazorApplication>(); builder.Modules .AddConditionalAppearance() .AddValidation(options => { options.AllowValidationDetailsAccess = false; }) .AddSecurityExtensions(options => options.CreateSecuritySystemUser = DXApplication1.Module.DatabaseUpdate.Updater.CreateUser) .Add<DXApplication1.Module.DXApplication1Module>() .Add<DXApplication1BlazorModule>(); builder.ObjectSpaceProviders .AddSecuredEFCore(options => options.PreFetchReferenceProperties()) .WithDbContext<DXApplication1.Module.BusinessObjects.DXApplication1EFCoreDbContext>((serviceProvider, options) => { // Uncomment this code to use an in-memory database. This database is recreated each time the server starts. With the in-memory database, you don't need to make a migration when the data model is changed. // Do not use this code in production environment to avoid data loss. // We recommend that you refer to the following help topic before you use an in-memory database: https://docs.microsoft.com/en-us/ef/core/testing/in-memory //options.UseInMemoryDatabase("InMemory"); string connectionString = null; if(Configuration.GetConnectionString("ConnectionString") != null) { connectionString = Configuration.GetConnectionString("ConnectionString"); } #if EASYTEST if(Configuration.GetConnectionString("EasyTestConnectionString") != null) { connectionString = Configuration.GetConnectionString("EasyTestConnectionString"); } #endif ArgumentNullException.ThrowIfNull(connectionString); options.UseSqlServer(connectionString); options.UseChangeTrackingProxies(); options.UseObjectSpaceLinkProxies(); options.UseLazyLoadingProxies(); }) .AddNonPersistent(); builder.Security .UseIntegratedMode(options => { options.Lockout.Enabled = true; options.RoleType = typeof(PermissionPolicyRole); // ApplicationUser descends from PermissionPolicyUser and supports the OAuth authentication. For more information, refer to the following topic: https://docs.devexpress.com/eXpressAppFramework/402197 // If your application uses PermissionPolicyUser or a custom user type, set the UserType property as follows: options.UserType = typeof(DXApplication1.Module.BusinessObjects.ApplicationUser); // ApplicationUserLoginInfo is only necessary for applications that use the ApplicationUser user type. // If you use PermissionPolicyUser or a custom user type, comment out the following line: options.UserLoginInfoType = typeof(DXApplication1.Module.BusinessObjects.ApplicationUserLoginInfo); options.Events.OnSecurityStrategyCreated += securityStrategy => { // Use the 'PermissionsReloadMode.NoCache' option to load the most recent permissions from the database once // for every DbContext instance when secured data is accessed through this instance for the first time. // Use the 'PermissionsReloadMode.CacheOnFirstAccess' option to reduce the number of database queries. // In this case, permission requests are loaded and cached when secured data is accessed for the first time // and used until the current user logs out. // See the following article for more details: https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Security.SecurityStrategy.PermissionsReloadMode. ((SecurityStrategy)securityStrategy).PermissionsReloadMode = PermissionsReloadMode.NoCache; }; }) .AddPasswordAuthentication(options => { options.IsSupportChangePassword = true; }); }); var authentication = services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; }); authentication.AddCookie(options => { options.LoginPath = "/LoginPage"; }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if(env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. To change this for production scenarios, see: https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseRequestLocalization(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseXaf(); app.UseEndpoints(endpoints => { endpoints.MapXafEndpoints(); endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); endpoints.MapControllers(); }); } }
XPO/DXApplication1.Module/DatabaseUpdate/Updater.cs
C#
using DevExpress.ExpressApp; using DevExpress.Data.Filtering; using DevExpress.Persistent.Base; using DevExpress.ExpressApp.Updating; using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.SystemModule; using DevExpress.ExpressApp.Security.Strategy; using DevExpress.Xpo; using DevExpress.ExpressApp.Xpo; using DevExpress.Persistent.BaseImpl; using DevExpress.Persistent.BaseImpl.PermissionPolicy; using DXApplication1.Module.BusinessObjects; using Microsoft.Extensions.DependencyInjection; using DevExpress.Persistent.Base.Security; using DevExpress.Persistent.Validation; using System.Security.AccessControl; namespace DXApplication1.Module.DatabaseUpdate; // For more typical usage scenarios, be sure to check out https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Updating.ModuleUpdater public class Updater : ModuleUpdater { public Updater(IObjectSpace objectSpace, Version currentDBVersion) : base(objectSpace, currentDBVersion) { } public static IAuthenticationStandardUser CreateUser(IObjectSpace objectSpace, string userName, string email, string password, bool isAdministrator) { if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(email)) { throw new UserFriendlyException("User Name and Email address are not specified!"); } var userManager = objectSpace.ServiceProvider.GetRequiredService<UserManager>(); if (userManager.FindUserByName<ApplicationUser>(objectSpace, userName) != null) { throw new UserFriendlyException("A user already exists with this name."); } if (objectSpace.FirstOrDefault<ApplicationUser>(user => user.Email == email) != null) { throw new UserFriendlyException("A user already exists with this email."); } var role = isAdministrator ? GetAdminRole(objectSpace) : GetDefaultRole(objectSpace); var result = userManager.CreateUser<ApplicationUser>(objectSpace, userName, password, (user) => { user.Email = email; user.Roles.Add(role); }); if (!result.Succeeded) { throw new UserFriendlyException("Error creating a new user."); } return result.User; } public override void UpdateDatabaseAfterUpdateSchema() { base.UpdateDatabaseAfterUpdateSchema(); // The code below creates users and roles for testing purposes only. // In production code, you can create users and assign roles to them automatically, as described in the following help topic: // https://docs.devexpress.com/eXpressAppFramework/119064/data-security-and-safety/security-system/authentication #if !RELEASE // If a role doesn't exist in the database, create this role var defaultRole = GetDefaultRole(ObjectSpace); var adminRole = GetAdminRole(ObjectSpace); ObjectSpace.CommitChanges(); //This line persists created object(s). string EmptyPassword = ""; var userManager = ObjectSpace.ServiceProvider.GetRequiredService<UserManager>(); if (userManager.FindUserByName<ApplicationUser>(ObjectSpace, "User") == null) { CreateUser(ObjectSpace, "User", "user@example.com", EmptyPassword, isAdministrator: false); } if (userManager.FindUserByName<ApplicationUser>(ObjectSpace, "Admin") == null) { CreateUser(ObjectSpace, "Admin", "admin@example.com", EmptyPassword, isAdministrator: true); } ObjectSpace.CommitChanges(); //This line persists created object(s). #endif } public override void UpdateDatabaseBeforeUpdateSchema() { base.UpdateDatabaseBeforeUpdateSchema(); //if(CurrentDBVersion < new Version("1.1.0.0") && CurrentDBVersion > new Version("0.0.0.0")) { // RenameColumn("DomainObject1Table", "OldColumnName", "NewColumnName"); //} } private static PermissionPolicyRole GetAdminRole(IObjectSpace objectSpace) { PermissionPolicyRole adminRole = objectSpace.FirstOrDefault<PermissionPolicyRole>(r => r.Name == "Administrators"); if(adminRole == null) { adminRole = objectSpace.CreateObject<PermissionPolicyRole>(); adminRole.Name = "Administrators"; adminRole.IsAdministrative = true; } return adminRole; } private static PermissionPolicyRole GetDefaultRole(IObjectSpace objectSpace) { PermissionPolicyRole defaultRole = objectSpace.FirstOrDefault<PermissionPolicyRole>(role => role.Name == "Default"); if(defaultRole == null) { defaultRole = objectSpace.CreateObject<PermissionPolicyRole>(); defaultRole.Name = "Default"; defaultRole.AddObjectPermissionFromLambda<ApplicationUser>(SecurityOperations.Read, cm => cm.Oid == (Guid)CurrentUserIdOperator.CurrentUserId(), SecurityPermissionState.Allow); defaultRole.AddNavigationPermission(@"Application/NavigationItems/Items/Default/Items/MyDetails", SecurityPermissionState.Allow); defaultRole.AddMemberPermissionFromLambda<ApplicationUser>(SecurityOperations.Write, "ChangePasswordOnFirstLogon", cm => cm.Oid == (Guid)CurrentUserIdOperator.CurrentUserId(), SecurityPermissionState.Allow); defaultRole.AddMemberPermissionFromLambda<ApplicationUser>(SecurityOperations.Write, "StoredPassword", cm => cm.Oid == (Guid)CurrentUserIdOperator.CurrentUserId(), SecurityPermissionState.Allow); defaultRole.AddTypePermissionsRecursively<PermissionPolicyRole>(SecurityOperations.Read, SecurityPermissionState.Deny); defaultRole.AddObjectPermission<ModelDifference>(SecurityOperations.ReadWriteAccess, "UserId = ToStr(CurrentUserId())", SecurityPermissionState.Allow); defaultRole.AddObjectPermission<ModelDifferenceAspect>(SecurityOperations.ReadWriteAccess, "Owner.UserId = ToStr(CurrentUserId())", SecurityPermissionState.Allow); defaultRole.AddTypePermissionsRecursively<ModelDifference>(SecurityOperations.Create, SecurityPermissionState.Allow); defaultRole.AddTypePermissionsRecursively<ModelDifferenceAspect>(SecurityOperations.Create, SecurityPermissionState.Allow); } return defaultRole; } }
XPO/DXApplication1.Blazor.Server/Startup.cs
C#
using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.ApplicationBuilder; using DevExpress.ExpressApp.Blazor.ApplicationBuilder; using DevExpress.ExpressApp.Blazor.Services; using DevExpress.Persistent.Base; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Components.Server.Circuits; using DevExpress.ExpressApp.Xpo; using DXApplication1.Blazor.Server.Services; using DevExpress.Persistent.BaseImpl.PermissionPolicy; namespace DXApplication1.Blazor.Server; public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddSingleton(typeof(Microsoft.AspNetCore.SignalR.HubConnectionHandler<>), typeof(ProxyHubConnectionHandler<>)); services.AddRazorPages(); services.AddServerSideBlazor(); services.AddHttpContextAccessor(); services.AddScoped<CircuitHandler, CircuitHandlerProxy>(); services.AddXaf(Configuration, builder => { builder.UseApplication<DXApplication1BlazorApplication>(); builder.Modules .AddConditionalAppearance() .AddValidation(options => { options.AllowValidationDetailsAccess = false; }) .AddSecurityExtensions(options => options.CreateSecuritySystemUser = DXApplication1.Module.DatabaseUpdate.Updater.CreateUser) .Add<DXApplication1.Module.DXApplication1Module>() .Add<DXApplication1BlazorModule>(); builder.ObjectSpaceProviders .AddSecuredXpo((serviceProvider, options) => { string connectionString = null; if(Configuration.GetConnectionString("ConnectionString") != null) { connectionString = Configuration.GetConnectionString("ConnectionString"); } #if EASYTEST if(Configuration.GetConnectionString("EasyTestConnectionString") != null) { connectionString = Configuration.GetConnectionString("EasyTestConnectionString"); } #endif ArgumentNullException.ThrowIfNull(connectionString); options.ConnectionString = connectionString; options.ThreadSafe = true; options.UseSharedDataStoreProvider = true; }) .AddNonPersistent(); builder.Security .UseIntegratedMode(options => { options.Lockout.Enabled = true; options.RoleType = typeof(PermissionPolicyRole); // ApplicationUser descends from PermissionPolicyUser and supports the OAuth authentication. For more information, refer to the following topic: https://docs.devexpress.com/eXpressAppFramework/402197 // If your application uses PermissionPolicyUser or a custom user type, set the UserType property as follows: options.UserType = typeof(DXApplication1.Module.BusinessObjects.ApplicationUser); // ApplicationUserLoginInfo is only necessary for applications that use the ApplicationUser user type. // If you use PermissionPolicyUser or a custom user type, comment out the following line: options.UserLoginInfoType = typeof(DXApplication1.Module.BusinessObjects.ApplicationUserLoginInfo); options.UseXpoPermissionsCaching(); options.Events.OnSecurityStrategyCreated += securityStrategy => { // Use the 'PermissionsReloadMode.NoCache' option to load the most recent permissions from the database once // for every Session instance when secured data is accessed through this instance for the first time. // Use the 'PermissionsReloadMode.CacheOnFirstAccess' option to reduce the number of database queries. // In this case, permission requests are loaded and cached when secured data is accessed for the first time // and used until the current user logs out. // See the following article for more details: https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Security.SecurityStrategy.PermissionsReloadMode. ((SecurityStrategy)securityStrategy).PermissionsReloadMode = PermissionsReloadMode.NoCache; }; }) .AddPasswordAuthentication(options => { options.IsSupportChangePassword = true; }); }); var authentication = services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; }); authentication.AddCookie(options => { options.LoginPath = "/LoginPage"; }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if(env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. To change this for production scenarios, see: https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseRequestLocalization(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseXaf(); app.UseEndpoints(endpoints => { endpoints.MapXafEndpoints(); endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); endpoints.MapControllers(); }); } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.