Reputation: 17108
I have below config
public static IEnumerable<IdentityResource> GetIdentityResources=>
new List<IdentityResource>
{
new IdentityResources.Profile(),
new IdentityResources.OpenId(),
new IdentityResources.Email(),
};
public static IEnumerable<ApiResource> ApiResources=>
new List<ApiResource>
{
new ApiResource(AuthorizePolicy.apiScope, "Falcon Api")
};
public static IEnumerable<Client> Clients(IConfiguration configuration) =>
new Client[]
{
new Client
{
ClientId = "Falcon_Identity_Server",
ClientName = "FalconIdentityServer",
AllowedCorsOrigins = CorsUris(configuration),
AllowedGrantTypes = GrantTypes.Code,
AllowAccessTokensViaBrowser = bool.Parse(configuration.GetSection("IdentityServer:Client:AllowAccessTokensViaBrowser").Value),
IdentityTokenLifetime = Int32.Parse(configuration.GetSection("IdentityServer:Client:IdentityTokenLifetime").Value),
AccessTokenLifetime = Int32.Parse(configuration.GetSection("IdentityServer:Client:AccessTokenLifetime").Value),
RequireConsent = bool.Parse(configuration.GetSection("IdentityServer:Client:RequireConsent").Value),
UpdateAccessTokenClaimsOnRefresh = bool.Parse(configuration.GetSection("IdentityServer:Client:UpdateAccessTokenClaimsOnRefresh").Value),
RedirectUris = LocalRedirectUris(configuration),
PostLogoutRedirectUris = LocalRedirectUris(configuration),
AllowedScopes = AllowedScopes(),
AllowOfflineAccess = bool.Parse(configuration.GetSection("IdentityServer:Client:AllowOfflineAccess").Value),
AccessTokenType = AccessTokenType.Jwt,
RequireClientSecret = bool.Parse(configuration.GetSection("IdentityServer:Client:RequireClientSecret").Value),
RequirePkce = bool.Parse(configuration.GetSection("IdentityServer:Client:RequirePkce").Value),
//AllowRememberConsent = true
}
};
private static ICollection<string> AllowedScopes()
{
return new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
AuthorizePolicy.apiScope
};
}
// API scopes represent values that describe scope of access and can be requested by the scope parameter (OAuth)
public static readonly IEnumerable<ApiScope> ApiScopes =
new[]
{
new ApiScope(IdentityServerConstants.StandardScopes.OpenId),
new ApiScope(IdentityServerConstants.StandardScopes.Profile),
new ApiScope(IdentityServerConstants.StandardScopes.Email),
new ApiScope(AuthorizePolicy.apiScope),
};
Profile service
public class ProfileService : IProfileService
{
private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory;
private readonly UserManager<ApplicationUser> _userManager;
private readonly ILogger<ProfileService> Logger;
public ProfileService(UserManager<ApplicationUser> userManager,
IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory,
ILogger<ProfileService> logger)
{
_userManager = userManager;
_claimsFactory = claimsFactory;
Logger = logger;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var sub = context.Subject?.GetSubjectId();
if (sub == null) throw new Exception("No sub claim present");
var user = await _userManager.FindByIdAsync(sub);
if (user == null)
{
Logger?.LogWarning("No user found matching subject Id: {0}", sub);
}
else
{
var principal = await _claimsFactory.CreateAsync(user);
if (principal == null) throw new Exception("ClaimsFactory failed to create a principal");
context.IssuedClaims.AddRange(principal.Claims);
}
}
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject?.GetSubjectId();
if (sub == null) throw new Exception("No subject Id claim present");
var user = await _userManager.FindByIdAsync(sub);
if (user == null)
{
Logger?.LogWarning("No user found matching subject Id: {0}", sub);
}
context.IsActive = user != null;
}
}
While accessing the claim in AuthorizationHandler
the user has the below claims
However, on the token it has more claims
{
"iss": "https://localhost:5001",
"nbf": 1651829483,
"iat": 1651829483,
"exp": 1651829683,
"scope": [
"openid",
"profile",
"email"
],
"amr": [
"pwd"
],
"client_id": "Falcon_Identity_Server",
"sub": "9717a359-f83b-43b3-97b3-2f04f1148988",
"auth_time": 1651828196,
"idp": "local",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "9717a359-f83b-43b3-97b3-2f04f1148988",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "[email protected]",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "[email protected]",
"AspNet.Identity.SecurityStamp": "1999ca9c-398d-4ffe-907a-b1f1b5e8cbfe",
"identityserver": "owner",
"fb_product": "owner",
"fb_order": "owner",
"fb_payment": "owner",
"sid": "215A4703E0D026F660C44D0BB7235EDA",
"jti": "D5989213C1F6D659141D57D07AC2EFDF"
}
Register the below jwt
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
// base-address of your identityserver
options.Authority = "https://localhost:5001";
// audience is optional, make sure you read the following paragraphs
// to understand your options
options.TokenValidationParameters.ValidateAudience = false;
// it's recommended to check the type header to avoid "JWT confusion" attacks
options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" };
});
Handler
public class IdentityServerUserClaimHandler : AuthorizationHandler<IdentityServerUserClaimRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
IdentityServerUserClaimRequirement requirement)
{
if (context.User.HasClaim(c => c.Type == requirement.ClaimType &&
c.Value == requirement.ClaimValue))
context.Succeed(requirement);
return Task.CompletedTask;
}
}
Upvotes: 0
Views: 2998
Reputation: 19941
By default ASP.NET don't pass all the claims from the token to the User (claimsPrincipal) because most of them are internal OpenID-Connect claims.
To get claims into the User object, then you need to manually map them using code like:
options.ClaimActions.MapUniqueJsonKey("website", "website");
options.ClaimActions.MapUniqueJsonKey("gender", "gender");
options.ClaimActions.MapUniqueJsonKey("birthdate", "birthdate");
(In AddJwtBearer or AddOpenIdconnect)
To complement this answer, I wrote a blog post that goes into more detail about this topic: Debugging OpenID Connect claim problems in ASP.NET Core
Upvotes: 1