问题
I'm setting up a client credential flow with my identity server to get an access token from a client. I'm able to get the access token with the following code,
Identity server configuration:
public void Configuration(IAppBuilder app) { app.Map("/identity", idsrvApp => { var corsPolicyService = new DefaultCorsPolicyService() { AllowAll = true }; var idServerServiceFactory = new IdentityServerServiceFactory() .UseInMemoryClients(Clients.Get()) .UseInMemoryScopes(Scopes.Get()) .UseInMemoryUsers(Users.Get()); var options = new IdentityServerOptions { Factory = idServerServiceFactory, SiteName = "Demo", IssuerUri = IdentityConstants.IssuerUri, PublicOrigin = IdentityConstants.STSOrigin, SigningCertificate = LoadCertificate() }; idsrvApp.UseIdentityServer(options); }); }
Identity Server - Client configuration:
public static class Clients { public static IEnumerable<Client> Get() { return new[] { new Client { ClientId = "ClientSDK", ClientName = "Client SDK (Client Credentials)", Flow = Flows.ClientCredentials, AllowAccessToAllScopes = true, ClientSecrets = new List<Secret>() { new Secret(IdentityConstants.ClientSecret.Sha256()) } } }; }
}
MVC Client:
var oAuth2Client = new TokenClient( IdentityConstants.STSTokenEndpoint, "ClientSDK", IdentityConstants.ClientSecret); var tokenResponse = oAuth2Client.RequestClientCredentialsAsync("MyScope").Result; return tokenResponse.AccessToken;
I'm able to get the access token(i.e. JWT). Can one please tell me how to add a unique key like (UserId) from my database, when the JWT is created with its claims data when the token is created.
回答1:
First, you need to create custom attribute "userId" on Azure Portal, and apply it for selected application. Then follow this example, Update user using Graph API
If you are using built in user flows, then you need to select "userId" for your application. If you are using custom policy, then following process. JWT token shows only output claims of Azure AD B2C custom policy. It is a multi steps process to create and update custom policy. Here is link to read more about How to create custom attribute
回答2:
You should implement custom user store for validating user and adding claims from database. Change startup code like below, Userrepository class represents database communication to authenticate user and get claims from database:
var idServerServiceFactory = new IdentityServerServiceFactory()
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get())
.AddCustomUserStore();
Add below classes and change according to your requirement:
public static class CustomIdentityServerBuilderExtensions
{
public static IIdentityServerBuilder AddCustomUserStore(this IIdentityServerBuilder builder)
{
builder.AddProfileService<UserProfileService>();
builder.AddResourceOwnerValidator<UserResourceOwnerPasswordValidator>();
return builder;
}
}
public class UserProfileService : IProfileService
{
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
UserRepository userRepository=new UserRepository();
var user = userRepository.GetUserById(int.Parse(context.Subject.GetSubjectId()));
if (user != null)
{
var userTokenModel = _mapper.Map<UserTokenModel>(user);
var claims = new List<Claim>();
claims.Add(new Claim("UserId", user.UserId));
// Add another claims here
context.IssuedClaims.AddRange(claims);
}
public async Task IsActiveAsync(IsActiveContext context)
{
}
}
public class UserResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
UserRepository userRepository=new UserRepository();
var userLoginStatus = userRepository.GetUserById(context.UserName, context.Password);
if (userLoginStatus != null)
{
context.Result = new GrantValidationResult(userLoginStatus.UserId.ToString(),
OidcConstants.AuthenticationMethods.Password);
}
else
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidClient,
"Wrong Credentials");
}
}
}
来源:https://stackoverflow.com/questions/61608289/openid-connect-how-to-add-custom-claims-data-in-the-client-credential-flow