问题
I want to include a claim by default in the access token retrieved when I Authenticate via IdSrv. The Claim Ticket
should always be included in the access token, as such I have created a new scope that is a resource scope and included Ticket
as a ScopeClaim
. However as you can see from the IdSrv logs when IdSrv is creating the access token and calls GetProfileDataAsync
the list of requested claims in the context is empty, and so no claims are added to the access token.
How can I include this claim into the access token by default?
I was under the impression that requesting a Resource
scope would allow the claims in the scope to be returned as part of the access token.
Scopes
public static List<Scope> Get()
{
return new List<Scope>
{
StandardScopes.OpenId //standard scope when dealing with open id connect
,
StandardScopes.OfflineAccess
,
new Scope
{
Name = "App",
DisplayName = "App",
Type = ScopeType.Identity,
Claims = new List<ScopeClaim>
{
new ScopeClaim
{
AlwaysIncludeInIdToken = false,
Name = "App",
Description = "Role Information"
},
// new ScopeClaim
// {
// AlwaysIncludeInIdToken = false,
// Name = "Ticket",
// Description = "Login ticket"
// }
},
IncludeAllClaimsForUser = false
},
new Scope
{
Name = "AppAccess",
DisplayName = "AppAccess",
Type = ScopeType.Resource,
Claims = new List<ScopeClaim>
{
new ScopeClaim
{
Name = "Ticket",
Description = "Login ticket",
}
},
IncludeAllClaimsForUser = true
}
};
Claims
public static List<Client> Get()
{
return new List<Client>
{
new Client
{
ClientName = "Hybrid Flow",
ClientId = "apphybrid",
Enabled = true,
Flow = Flows.Hybrid,
AllowAccessToAllScopes = true,
IdentityTokenLifetime = 120,
AccessTokenLifetime = 400,
RequireConsent = false,
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
RedirectUris = new List<string>
{
"localhost/App/login/Login.mr"
},
PostLogoutRedirectUris = new List<string>
{
"localhost/App/login/Login.mr"
},
AllowedScopes = new List<string>
{
Constants.StandardScopes.OpenId,
Constants.StandardScopes.OfflineAccess,
"App",
"AppAccess"
}
}
};
}
IDSrv Config
public override Task AuthenticateLocalAsync(LocalAuthenticationContext context)
{
var securityServiceProxy = new SecurityServiceProxy(new ServiceHeadersParameters { UserHostAddress = Ctx.Request.Host.Value });
var ticket = securityServiceProxy.UseServiceClient(serviceClient => serviceClient.AuthenticateUser(context.UserName, context.Password, Configuration.ProviderCode));
if (!ticket.IsValid())
{
context.AuthenticateResult = new AuthenticateResult("Invalid credentials");
return Task.FromResult(0);
}
var claims = new List<Claim> {
new Claim(GlobalConstant.TicketClaim, ticket.Ticket.ToString())
};
context.AuthenticateResult = new AuthenticateResult(
ticket.UserObjId.ToString(),
context.UserName,
claims: claims,
authenticationMethod: Constants.AuthenticationMethods.Password,
identityProvider: Configuration.ProviderCode
);
return Task.FromResult(0);
}
public override Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var applicationDto = GetApplicationDto(context);
var claims = new List<Claim>
{
new Claim(Constants.ClaimTypes.Subject, context.Subject.GetSubjectId()),
};
Log.Debug("The requested claims...");
if (context.RequestedClaimTypes == null)
{
Log.Debug("Requested Claims is null");
}
else
{
foreach (var x in context.RequestedClaimTypes)
{
Log.Debug($"Claims {x}");
}
if (context.RequestedClaimTypes.Contains(GlobalConstant.TicketClaim))
claims.Add(context.Subject.Claims.Where(x => x.Type.Equals(GlobalConstant.TicketClaim)).FirstOrDefault());
if (context.RequestedClaimTypes.Contains(GlobalConstant.ApplicationClaim))
claims.Add(new Claim(GlobalConstant.ApplicationClaim, applicationDto.Jsonify()));
}
// set the issued claims - these are the ones that were requested, if available
context.IssuedClaims = claims;
Log.Debug("Finished ProfileDataAsync");
return Task.FromResult(0);
}
private ApplicationDto GetApplicationDto(ProfileDataRequestContext context)
{
var securityServiceProxy = new SecurityServiceProxy(new ServiceHeadersParameters { UserHostAddress = Ctx.Request.Host.Value });
return securityServiceProxy.UseServiceClient(serviceClient => serviceClient.RetrieveAuthenticatedUser(GetUserTicketFromContext(context)));
}
private static UserTicketDto GetUserTicketFromContext(ProfileDataRequestContext context)
{
Log.Debug("The claims in the context...");
foreach(var x in context.Subject.Claims)
{
Log.Debug($"Cliams {x.Type} {x.Value}");
}
var ticketString = context.Subject.Claims.Where(x => x.Type.Equals(GlobalConstant.TicketClaim)).FirstOrDefault()?.Value;
var userIdString = context.Subject.GetSubjectId();
Guid Ticket, UserId;
if(Guid.TryParse(ticketString, out Ticket) && Guid.TryParse(userIdString, out UserId))
{
return new UserTicketDto { Ticket = Ticket, UserObjId = UserId };
}
return new UserTicketDto();
}
Web config
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
AntiForgeryConfig.UniqueClaimTypeIdentifier = IdentityModel.JwtClaimTypes.Name;
app.Use(async (ctx, next) => { await next(); });
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = OAuthConstant.Client,
RedirectUri = "localhost/App/login/Login.mr",
PostLogoutRedirectUri = "localhost/App/login/Login.mr",
Authority = "localhost/Oauth2server/securetoken",
SignInAsAuthenticationType = "Cookies",
ResponseType = "token code id_token",
Scope = "OpenId App offline_access AppAccess",
ClientSecret = "secret",
UseTokenLifetime = false,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthorizationCodeReceived = IdentityServerClient.HandleOther,
SecurityTokenReceived = IdentityServerClient.HandleOther,
MessageReceived = IdentityServerClient.HandleOther,
AuthenticationFailed = IdentityServerClient.HandleOther,
RedirectToIdentityProvider = IdentityServerClient.HandleRedirectToIdentityProvider,
SecurityTokenValidated = IdentityServerClient.HandleSecurityTokenValidated
}
});
Logs
2016-06-15 12:04:51.943 -05:00 [Information] Login page submitted
2016-06-15 12:04:55.320 -05:00 [Information] Login credentials successfully validated by user service
2016-06-15 12:04:55.332 -05:00 [Information] Calling PostAuthenticateAsync on the user service
2016-06-15 12:04:55.338 -05:00 [Information] issuing primary signin cookie
2016-06-15 12:04:55.344 -05:00 [Information] redirecting to: http://localhost/OAuth2Server/securetoken/connect/authorize?client_id=apphybrid&redirect_uri=http:%2F%2Flocalhost%2Fapp%2FLogin%2FLogin.mr&response_mode=form_post&response_type=code id_token token&scope=App openid offline_access AppAccess&state=OpenIdConnect.AuthenticationProperties%3DebxFcJnjMiMq2m1gPqBsYlrBWdLct2kaJSYn-s0nxImnff-37i4t8Wa3wAJewJGFe9msgeeqJDKtR1gwwfA0e8Pdd6RNAi6YPo_CqT4l5zV8ifohYQVN9TrWfLXITXuKId9IW2cCeRQL6d8uWfkzSANqAGSbSGJYZ5pgOLULQresbAiJ7N77FgBmgrVtX4hDQuwGGL5vZFCb_C5tjl8_ezH12w8zQfifKuLwjaDmOSGYyo2AqpowQXXeSSSDgKBF&nonce=636016067018002117.MWY4MGVjOWItYTFjYS00MTVlLTg4MDYtMjYxYjkwMWEzNzU4ZWViNzEyNTQtMjE0Mi00MjYzLTk2ZjMtODdhYmIxYTM5Mjg5
2016-06-15 12:04:55.368 -05:00 [Debug] Incoming request: /securetoken/connect/authorize
2016-06-15 12:04:55.381 -05:00 [Information] Start authorize request
2016-06-15 12:04:55.381 -05:00 [Information] Start authorize request protocol validation
2016-06-15 12:04:55.381 -05:00 [Information] "Authorize request validation success"
"{
\"ClientId\": \"apphybrid\",
\"ClientName\": \"app Hybrid Flow\",
\"RedirectUri\": \"http://localhost/app/Login/Login.mr\",
\"AllowedRedirectUris\": [
\"http://localhost/app/Login/Login.mr\"
],
\"SubjectId\": \"783bf872-b864-4042-853d-04fbcb7a505a\",
\"ResponseType\": \"code id_token token\",
\"ResponseMode\": \"form_post\",
\"Flow\": \"Hybrid\",
\"RequestedScopes\": \"app openid offline_access appAccess\",
\"State\": \"OpenIdConnect.AuthenticationProperties=ebxFcJnjMiMq2m1gPqBsYlrBWdLct2kaJSYn-s0nxImnff-37i4t8Wa3wAJewJGFe9msgeeqJDKtR1gwwfA0e8Pdd6RNAi6YPo_CqT4l5zV8ifohYQVN9TrWfLXITXuKId9IW2cCeRQL6d8uWfkzSANqAGSbSGJYZ5pgOLULQresbAiJ7N77FgBmgrVtX4hDQuwGGL5vZFCb_C5tjl8_ezH12w8zQfifKuLwjaDmOSGYyo2AqpowQXXeSSSDgKBF\",
\"Nonce\": \"636016067018002117.MWY4MGVjOWItYTFjYS00MTVlLTg4MDYtMjYxYjkwMWEzNzU4ZWViNzEyNTQtMjE0Mi00MjYzLTk2ZjMtODdhYmIxYTM5Mjg5\",
\"SessionId\": \"e79cd97a339b4513b45038e7755c1b88\",
\"Raw\": {
\"client_id\": \"apphybrid\",
\"redirect_uri\": \"http://localhost/app/Login/Login.mr\",
\"response_mode\": \"form_post\",
\"response_type\": \"code id_token token\",
\"scope\": \"app openid offline_access appAccess\",
\"state\": \"OpenIdConnect.AuthenticationProperties=ebxFcJnjMiMq2m1gPqBsYlrBWdLct2kaJSYn-s0nxImnff-37i4t8Wa3wAJewJGFe9msgeeqJDKtR1gwwfA0e8Pdd6RNAi6YPo_CqT4l5zV8ifohYQVN9TrWfLXITXuKId9IW2cCeRQL6d8uWfkzSANqAGSbSGJYZ5pgOLULQresbAiJ7N77FgBmgrVtX4hDQuwGGL5vZFCb_C5tjl8_ezH12w8zQfifKuLwjaDmOSGYyo2AqpowQXXeSSSDgKBF\",
\"nonce\": \"636016067018002117.MWY4MGVjOWItYTFjYS00MTVlLTg4MDYtMjYxYjkwMWEzNzU4ZWViNzEyNTQtMjE0Mi00MjYzLTk2ZjMtODdhYmIxYTM5Mjg5\"
}
}"
2016-06-15 12:04:55.399 -05:00 [Information] Creating Hybrid Flow response.
2016-06-15 12:04:55.412 -05:00 [Information] Creating Implicit Flow response.
2016-06-15 12:04:55.416 -05:00 [Debug] Creating access token
2016-06-15 12:04:55.424 -05:00 [Debug] Getting ProfileDataAsync
2016-06-15 12:04:55.436 -05:00 [Debug] The claims in the context...
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams sub 783bf872-b864-4042-853d-04fbcb7a505a
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams name dev.guser
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams amr password
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams idp IDSRV
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams auth_time 1466010295
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams ticket fc05cd84-7756-4ec5-ac3c-53ac6d4d5e2a
2016-06-15 12:04:55.975 -05:00 [Debug] The requseted claims...
2016-06-15 12:04:55.976 -05:00 [Debug] Requested Claims Is Null
2016-06-15 12:04:55.976 -05:00 [Debug] Finished ProfileDataAsync
2016-06-15 12:04:55.982 -05:00 [Debug] Creating JWT access token
2016-06-15 12:04:56.049 -05:00 [Debug] Creating identity token
2016-06-15 12:04:56.054 -05:00 [Information] Getting claims for identity token for subject: 783bf872-b864-4042-853d-04fbcb7a505a
2016-06-15 12:04:56.054 -05:00 [Debug] Getting ProfileDataAsync
2016-06-15 12:04:56.066 -05:00 [Debug] The claims in the context...
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams sub 783bf872-b864-4042-853d-04fbcb7a505a
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams name dev.guser
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams amr password
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams idp IDSRV
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams auth_time 1466010295
2016-06-15 12:04:56.066 -05:00 [Debug] Cliams ticket fc05cd84-7756-4ec5-ac3c-53ac6d4d5e2a
2016-06-15 12:04:56.338 -05:00 [Debug] The requseted claims...
2016-06-15 12:04:56.338 -05:00 [Debug] Cliams sub
2016-06-15 12:04:56.338 -05:00 [Debug] Finished ProfileDataAsync
2016-06-15 12:04:56.338 -05:00 [Debug] Creating JWT identity token
2016-06-15 12:04:56.344 -05:00 [Debug] Adding client "apphybrid" to client list cookie for subject "783bf872-b864-4042-853d-04fbcb7a505a"
2016-06-15 12:04:56.349 -05:00 [Information] End authorize request
2016-06-15 12:04:56.352 -05:00 [Information] Posting to http://localhost/app/Login/Login.mr
2016-06-15 12:04:56.352 -05:00 [Debug] Using AssetManager to render authorization response HTML
2016-06-15 12:04:56.388 -05:00 [Debug] Incoming request: /securetoken/assets/app.FormPostResponse.js
//Web
2016-06-15 12:04:56,422 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Triggered MessageReceivedNotification`2 notification
2016-06-15 12:04:56,426 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Triggered SecurityTokenReceivedNotification`2 notification
2016-06-15 12:04:56,487 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Triggered SecurityTokenValidated notification
2016-06-15 12:04:56,487 [16] DEBUG app.Web.IdentityServer.IdentityServerClient The Claims in the identity
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: iss http://localhost/OAuth2Server/securetoken
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: aud apphybrid
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: exp 1466010416
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: nbf 1466010296
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: nonce 636016067018002117.MWY4MGVjOWItYTFjYS00MTVlLTg4MDYtMjYxYjkwMWEzNzU4ZWViNzEyNTQtMjE0Mi00MjYzLTk2ZjMtODdhYmIxYTM5Mjg5
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: iat 1466010296
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: at_hash 6pIu3P1cEeTQJMcK8Gcnhw
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: c_hash VsSw9HC0xyodlSkSCZefLw
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: sid e79cd97a339b4513b45038e7755c1b88
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: sub 783bf872-b864-4042-853d-04fbcb7a505a
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: auth_time 1466010295
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: idp IDSRV
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Claims: amr password
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient The access token: [Omitted]
2016-06-15 12:04:56,488 [16] DEBUG app.Web.IdentityServer.IdentityServerClient The id token: [Omitted]
2016-06-15 12:04:56,491 [16] DEBUG app.Web.IdentityServer.IdentityServerClient Triggered AuthenticationFailedNotification`2 notification
//Web
//Logs
The log output in question...
2016-06-15 12:04:55.412 -05:00 [Information] Creating Implicit Flow response.
2016-06-15 12:04:55.416 -05:00 [Debug] Creating access token
2016-06-15 12:04:55.424 -05:00 [Debug] Getting ProfileDataAsync
2016-06-15 12:04:55.436 -05:00 [Debug] The claims in the context...
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams sub 783bf872-b864-4042-853d-04fbcb7a505a
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams name dev.guser
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams amr password
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams idp IDSRV
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams auth_time 1466010295
2016-06-15 12:04:55.437 -05:00 [Debug] Cliams ticket fc05cd84-7756-4ec5-ac3c-53ac6d4d5e2a <- Has the claim I want
2016-06-15 12:04:55.975 -05:00 [Debug] The requseted claims...
2016-06-15 12:04:55.976 -05:00 [Debug] Requested Claims Is Null <- but this needs to indicate that we want that claim...
2016-06-15 12:04:55.976 -05:00 [Debug] Finished ProfileDataAsync
回答1:
Update 2: Ok now that I look closer, you have IncludeAllClaimsForUser = true
. In the GetProfileData there's a comparable flag on the context. I suspect that's why you have no claims in the collection.
Update 1: Claims that you want to go into tokens should be added in GetProfile
not in the AuthenticateResult
in the AuthentivcateLocal
method.
Original: Change the type of scope from Identity
to Resource
. This affects which tokens the claims go into.
来源:https://stackoverflow.com/questions/37841927/how-do-i-include-claims-into-the-access-token-retrieved-from-the-authorize-endpo