Open Closed

Customizing Authentication Logic in ABP #10589


User avatar
0
vmquang95 created

I have a project integrated with another system (let’s call it System B). System B is responsible for managing user information and provides us with a sessionCode to identify users. When the sessionCode is valid, System B returns the full user information.

In our project, we plan to use this sessionCode for authentication by passing it through the request header. Technically, we can customize this behavior using Middleware or an ActionFilter to validate the sessionCode.

However, we would still like to leverage ABP’s built-in user context, specifically ICurrentUser, for use in Domain Services and other business logic.

So my question is: Is there a way to customize the authentication mechanism in ABP so that we can validate the sessionCode and still populate ICurrentUser properly?

Thank you.

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

2 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • Yes. In ABP, ICurrentUser is populated from the current ClaimsPrincipal (typically HttpContext.User in an HTTP request). So the correct way is to implement your sessionCode validation as a real ASP.NET Core authentication scheme that creates a ClaimsPrincipal when the header is valid. Once you do that, ABP will automatically see the authenticated principal and ICurrentUser will work in application/domain services, auditing, authorization, etc.

    • Implement a custom authentication handler reading your header (example: X-Session-Code), call System B to validate it and fetch user info, then create claims ABP understands (at minimum: AbpClaimTypes.UserId, optionally username, roles, tenant, etc.).

    using System.Security.Claims;
    using System.Text.Encodings.Web;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.Extensions.Options;
    using Volo.Abp.Security.Claims;
    
    public sealed class SessionCodeAuthHandler
        : AuthenticationHandler<AuthenticationSchemeOptions>
    {
        public const string SchemeName = "SessionCode";
    
        public SessionCodeAuthHandler(
            IOptionsMonitor<AuthenticationSchemeOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder)
            : base(options, logger, encoder)
        {
        }
    
        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            if (!Request.Headers.TryGetValue("X-Session-Code", out var values))
            {
                return AuthenticateResult.NoResult();
            }
    
            var sessionCode = values.ToString();
            if (string.IsNullOrWhiteSpace(sessionCode))
            {
                return AuthenticateResult.NoResult();
            }
    
            // 1) Validate against System B and get user info
            //    (Pseudo-code; replace with your actual HTTP call / SDK)
            var externalUser = await ValidateWithSystemBAsync(sessionCode);
            if (externalUser is null)
            {
                return AuthenticateResult.Fail("Invalid sessionCode");
            }
    
            // 2) Build ClaimsPrincipal so ABP's ICurrentUser can read it
            var claims = new List<Claim>
            {
                new(AbpClaimTypes.UserId, externalUser.UserId.ToString()),
                new(AbpClaimTypes.UserName, externalUser.UserName ?? externalUser.UserId.ToString()),
            };
    
            // Optional: tenant
            // claims.Add(new Claim(AbpClaimTypes.TenantId, externalUser.TenantId.ToString()));
    
            // Optional: roles
            // foreach (var role in externalUser.Roles) claims.Add(new Claim(AbpClaimTypes.Role, role));
    
            var identity = new ClaimsIdentity(claims, Scheme.Name);
            var principal = new ClaimsPrincipal(identity);
            var ticket = new AuthenticationTicket(principal, Scheme.Name);
    
            return AuthenticateResult.Success(ticket);
        }
    
        private Task<dynamic?> ValidateWithSystemBAsync(string sessionCode)
        {
            // Implement: call System B, return null if invalid, otherwise user payload.
            throw new NotImplementedException();
        }
    }
    
    • Register and use this scheme (in your HttpApiHost / web project module startup):
    using Microsoft.AspNetCore.Authentication;
    using Volo.Abp.Modularity;
    
    [DependsOn(/* your deps */)]
    public class MyHttpApiHostModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            context.Services
                .AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = SessionCodeAuthHandler.SchemeName;
                    options.DefaultChallengeScheme = SessionCodeAuthHandler.SchemeName;
                })
                .AddScheme<AuthenticationSchemeOptions, SessionCodeAuthHandler>(
                    SessionCodeAuthHandler.SchemeName,
                    _ => { }
                );
        }
    }
    
    • Ensure the ASP.NET Core authentication/authorization middleware runs (ABP templates already do). After that:

      • Your endpoints can use [Authorize].
      • ICurrentUser.Id, ICurrentUser.UserName, ICurrentUser.Roles, etc. will be populated based on the claims you created.
    • Alternative (only for special cases like background jobs / manual flows): you can set the principal explicitly for a scope using ICurrentPrincipalAccessor.Change(newPrincipal), but for HTTP requests the proper/clean approach is the custom authentication scheme described above, so everything (authorization, auditing, ICurrentUser) is consistent.

    Links:

    • https://abp.io/docs/latest/framework/infrastructure/current-user
    • https://abp.io/community/articles/i3uu1m7g

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    vmquang95 created

    Thank you.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 28, 2026, 11:44
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.