Skip to main content

User Logon and Authentication

  • 5 minutes to read

The Security System supports the following authentication techniques:

When you create a new XAF application, select an appropriate authentication type on the Choose Security page:

The Choose Security page in the Solution Wizard

To enable authentication in an existing application, refer to the following sections:

Windows Active Directory Authentication

With Active Directory Authentication, Windows checks the user identity, and XAF does not store user passwords in the database. The user name is obtained from the WindowsIdentity object and includes the computer or domain name (for example, COMPUTERNAME\UserName or DOMAINNAME\UserName). You can enable the AuthenticationActiveDirectory.CreateUserAutomatically option to create a new user object automatically when a user logs into the application for the first time.

For testing purposes, the Security System creates a new user object for your Windows account and assigns the administrative role to it when you start the application for the first time in DEBUG mode with the CreateUserAutomatically option enabled. In production code, the Security System does not create a new role or assign a role to a newly created user. In this case, you can assign a role manually in the Administrative UI or in the database directly, or specify the SecurityStrategyComplex.NewUserRoleName property. For further customization, you can handle the AuthenticationActiveDirectory.CustomCreateUser event (for example, you can automatically create restricted accounts associated with a specific default role).

Enable Active Directory Authentication

WinForms or ASP.NET Web Forms + .NET Framework

Invoke the Application Designer and drop the SecurityStrategyComplex and AuthenticationActiveDirectory components from the Visual Studio Toolbox to the designer’s Security pane:

Security_UseSecurityStrategyComplex

WinForms (2-Tier Security) or ASP.NET Core Blazor + .NET 6

Files: ASP.NET Core Blazor - MySolution.Blazor.Server\Startup.cs WinForms - MySolution.Win\Startup.cs

// ...
builder.Security
    .UseIntegratedMode(options => {
        // ...
        // Assign a role with the 'Default' name to new users.
        options.NewUserRoleName = "Default";
        // ...
    })
    .AddWindowsAuthentication(options => {
        // Enable auto-creation of new users.
        options.CreateUserAutomatically();
        // Customize new user auto-creation.
        options.Events.CustomCreateUser = (e) => {
            // ...
        };
    });
// ...

WinForms (Middle-Tier Security) or Web API + .NET

Files: Middle Tier Server - MySolution.MiddleTier\Startup.cs Web API Service - MySolution.WebApi\Startup.cs

// ...
services.AddXafAspNetCoreSecurity(Configuration, options => {
    // Assign a role with the 'Default' name to new users.
    options.NewUserRoleName = "Default";
    })
    .AddAuthenticationActiveDirectory(options => {
        // Enable auto-creation of new users.
        options.CreateUserAutomatically = true;
        // Customize new user auto-creation.
        options.Events.CustomCreateUser = (e) => {
            // ...
        };
    });
// ...

Standard Authentication

With Standard Authentication, the Security System uses the internal XAF authentication mechanism and stores user credentials in the application’s database. Users need to input their name and password in the login form before application startup.

Note

You can customize the authentication process and add extra logon parameters. The following help section describes how to do this: Customize Standard Authentication Behavior and Supply Additional Logon Parameters (.NET Applications).

For testing purposes, XAF generates the administrative and non-administrative user objects (Admin and User) with empty passwords. In production code, create users and assign roles to them in the Administrative UI or database directly.

Tip

To protect your applications from brute force attacks, XAF includes user lockout functionality. For more information, refer to the following topic: ISecurityUserLockout.

Enable Standard Authentication

WinForms or ASP.NET Web Forms + .NET Framework

Invoke the Application Designer and drop the SecurityStrategyComplex and AuthenticationActiveDirectory components from the Visual Studio Toolbox to the designer’s Security pane.

Security_UseSecurityStrategyComplex

WinForms (2-Tier Security) or ASP.NET Core Blazor + .NET 6

Files: ASP.NET Core Blazor - MySolution.Blazor.Server\Startup.cs WinForms - MySolution.Win\Startup.cs

// ...
builder.Security
    .UseIntegratedMode(options => {
        // ...
    })
    .AddPasswordAuthentication(options => {
        options.IsSupportChangePassword = true;
        // ...
    });
// ...

WinForms (Middle-Tier Security) or Web API + .NET

Files: Middle Tier Server - MySolution.MiddleTier\Startup.cs Web API Service - MySolution.WebApi\Startup.cs

// ...
services.AddXafAspNetCoreSecurity(Configuration, options => {
        //...
    })
    .AddAuthenticationStandard(options => {
        options.IsSupportChangePassword = true;
    });
// ...

OAuth2 and Custom Authentication

The following examples demonstrate custom authentication implementations:

Authenticate a User in Code (Blazor, Web API Service)

XAF supports API that you can use to access and manage application users as well as authenticate users. This API includes the following services:

UserManager
Exposes API required to manage user objects in the database.
SignInManager
Exposes API required to sign a user into an application.

The following code snippet demonstrates how to use API that the UserManager and SignInManager services expose to sign into a nested scope and execute a controller’s action on a service user’s behalf (user impersonation):

Note

Note that the user impersonation technique demonstrated below is not supported for WinForms applications.

In Blazor applications, the demonstrated technique is not compatible with the static API exposed by the SecuritySystem class. This is because the SecuritySystem class’s methods always operate on the XAF application instance rather than a scope, so these methods are not affected by impersonation. To avoid faulty behavior in application logic that uses impersonation, ensure that this logic never uses the static API exposed by the SecuritySystem class.

using DevExpress.ExpressApp.Actions;
using DevExpress.ExpressApp.Security;
using DevExpress.Persistent.Base;
// ...
public partial class MyController : ViewController<ListView> {
    SimpleAction myAction;
    IServiceScopeFactory serviceScopeFactory;

    [ActivatorUtilitiesConstructor]
    public MyController(IServiceProvider serviceProvider) : this() {
        // ...
        myAction.Execute += MyAction_Execute;
        serviceScopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>();
    }
    // ...
    private void MyAction_Execute(object sender, SimpleActionExecuteEventArgs e) {
        // ...
        // Create a nested service scope whithin which to establish a separate login session. 
        using (IServiceScope impersonationScope = serviceScopeFactory.CreateScope()) {
            // Use the UserManager to obtain the "ServiceUser" user object.
            using IObjectSpace nonSecuredObjectSpace = impersonationScope.ServiceProvider
                .GetRequiredService<INonSecuredObjectSpaceFactory>().CreateNonSecuredObjectSpace<ApplicationUser>();
            ApplicationUser serviceUser = impersonationScope.ServiceProvider
                .GetRequiredService<UserManager>().FindUserByName<ApplicationUser>(nonSecuredObjectSpace, "ServiceUser");

            // Sign in as "ServiceUser" to the nested scope.
            SignInManager signInManager = impersonationScope.ServiceProvider.GetService<SignInManager>();
            signInManager.SignIn(serviceUser);

            // Obtain an Object Space from the nested scope and use this Object Space
            // to manipulate business objects on the "ServiceUser" user's behalf.
            using IObjectSpace objectSpace = impersonationScope.ServiceProvider
                .GetRequiredService<IObjectSpaceFactory>().CreateObjectSpace<MyActionPerMonth>();
            // ...
        }
    }
}