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.
2 Answer(s)
-
0
Yes. In ABP,
ICurrentUseris populated from the currentClaimsPrincipal(typicallyHttpContext.Userin an HTTP request). So the correct way is to implement yoursessionCodevalidation as a real ASP.NET Core authentication scheme that creates aClaimsPrincipalwhen the header is valid. Once you do that, ABP will automatically see the authenticated principal andICurrentUserwill 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.
- Your endpoints can use
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)