В моем приложении .net core 2.2 MVC Web Api у меня есть конечная точка Token для моего клиентского приложения Angular.Я использую OpenIddictCore для аутентификации.Я не использую токены JWT, я использую непрозрачные токены по умолчанию с OpenIddict и хочу использовать роли и утверждения для защиты маршрутов в моем угловом приложении.Когда я запрашиваю токен из моей конечной точки Token в 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;
}
}
Если этот подход неверен, пожалуйста, сообщите мне.Я просто застрял.Пытаюсь реализовать это часами, и теперь я не чувствую свой мозг.