在我的.net core 2.2 MVC Web Api应用程序中,我有一个Angular客户端应用程序的令牌终结点。我正在使用OpenIddictCore进行身份验证。我没有使用JWT令牌,而是将默认的不透明令牌与OpenIddict一起使用,我想使用角色和声明来保护我的角度应用程序上的路由。当我从Web Api的令牌端点请求令牌时,得到以下结果:
{
"token_type":"Bearer",
"access_token":"{access token here}",
"expires_in":3600
}
没有提供我有关角色的信息。是否有任何适当的方法来获得像这样的JSON响应:
{
"token_type":"Bearer",
"access_token":"{access token here}",
"expires_in":3600,
"roles":["ResourceEditor","ResourceViewer"... etc]
}
我已经搜索了很多,但是找不到任何东西。因为我一直在寻找解决方案。
一切正常,只要授权,一切都会正常。我的启动配置是:
services.AddDbContext<xxDbContext>(opt =>
{
opt.UseOpenIddict<Guid>();
opt.UseSqlServer(
@"Server=xxServer;Database=xxDB;User Id=xxUser;Password=xxPassword");
});
services.Configure<IdentityOptions>(opt =>
{
opt.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
opt.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
opt.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
opt.Password.RequireDigit = true;
opt.Password.RequiredLength = 8;
opt.Password.RequireLowercase = true;
opt.Password.RequireUppercase = true;
opt.Password.RequireNonAlphanumeric = false;
//opt.SignIn.RequireConfirmedEmail = true;
});
services.AddIdentity<UserEntity, UserRoleEntity>()
.AddEntityFrameworkStores<xxDbContext>()
.AddDefaultTokenProviders();
// Add OpenIddict services
services.AddOpenIddict(opt =>
{
opt.AddCore(conf => { conf.UseEntityFrameworkCore().UseDbContext<xxDbContext>(); });
opt.AddServer(conf =>
{
conf.UseMvc();
conf.EnableTokenEndpoint("/api/token");
conf.AllowPasswordFlow();
conf.AcceptAnonymousClients();
conf.RegisterClaims(OpenIdConnectConstants.Claims.Role,OpenIdConnectConstants.Claims.Username);
//conf.UseJsonWebTokens();
//this doesn't works so I keep going with opaque tokens
//conf.AddSigningCertificate(
// assembly: typeof(Startup).GetTypeInfo().Assembly,
// resource: "path to .pfx",
// password: "secret");
});
opt.AddValidation();
});
services.AddAuthentication(options =>
{
options.DefaultScheme = OpenIddictValidationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = OpenIddictValidationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIddictValidationDefaults.AuthenticationScheme;
});
我的令牌终结点是:
[Route("api/[controller]")]
public class TokenController : Controller
{
private readonly IOptions<IdentityOptions> _identityOptions;
private readonly SignInManager<UserEntity> _signInManager;
private readonly UserManager<UserEntity> _userManager;
public TokenController(IOptions<IdentityOptions> identityOptions, SignInManager<UserEntity> signInManager,
UserManager<UserEntity> userManager)
{
_identityOptions = identityOptions;
_signInManager = signInManager;
_userManager = userManager;
}
[HttpPost(Name = nameof(TokenExchangeAsync))]
public async Task<IActionResult> TokenExchangeAsync(
OpenIdConnectRequest request,
CancellationToken ct)
{
if (!request.IsPasswordGrantType())
{
return BadRequest(new OpenIdConnectResponse()
{
Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
ErrorDescription = "The specified grant type is not supported"
});
}
var user = await _userManager.FindByNameAsync(request.Username);
if (user == null)
return BadRequest(new OpenIdConnectResponse()
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The username or password is invalid"
});
if (!await _signInManager.CanSignInAsync(user))
return BadRequest(new OpenIdConnectResponse()
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The specified user is not allowed to sign in"
});
// Ensure the user is not already locked out
if (_userManager.SupportsUserLockout && await _userManager.IsLockedOutAsync(user))
{
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The username or password is invalid."
});
}
if (!await _userManager.CheckPasswordAsync(user, request.Password))
{
if (_userManager.SupportsUserLockout)
{
await _userManager.AccessFailedAsync(user);
}
return BadRequest(new OpenIdConnectResponse
{
Error = OpenIdConnectConstants.Errors.InvalidGrant,
ErrorDescription = "The username or password is invalid."
});
}
if (_userManager.SupportsUserLockout)
{
await _userManager.ResetAccessFailedCountAsync(user);
}
// Create a new authentication ticket w/ the user identity
var ticket = await CreateTicketAsync(request, user);
return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
}
private async Task<AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, UserEntity user)
{
var principal = await _signInManager.CreateUserPrincipalAsync(user);
var ticket = new AuthenticationTicket(principal,
new AuthenticationProperties(),
OpenIdConnectServerDefaults.AuthenticationScheme);
foreach (var claim in ticket.Principal.Claims)
{
if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType) continue;
claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken);
}
return ticket;
}
}
如果此方法不正确,请告诉我。我只是被卡住了。试图实施此方法数小时,现在我无法感觉到我的大脑。