如何将'scope'值映射到标识声明?



我已经指定了一个授权策略,需要范围为my_custom_value,例如

services.AddAuthorization(AuthConfig.GetAuthorizationOptions);
// ...
public static void GetAuthorizationOptions(AuthorizationOptions options)
{
options.AddPolicy("MyPolicy", policy =>
{
policy.RequireScope("my_custom_value");
});

MyPolicy保护的端点的请求失败,因为主体不包含任何作用域

我可以看到我的验证令牌有以下作用域:

"scope": [
"openid",
"profile",
"my_custom_value",
"offline_access"
],

这些似乎没有被映射到委托人的索赔。当我稍后在用户试图访问受保护的端点时检查声明时,发现没有作用域。

policy.RequireAssertion(context =>
{
if (context.User.HasClaim(c => c.Type == "scope")) // <-- always false
{
if (context.User.HasClaim(c => c.Value == "my_custom_value"))
{
return true;
}
}

为什么没有映射作用域?我需要做些什么来映射它们?

作为参考,我已经用

试过了
options.ClaimActions.MapUniqueJsonKey(JwtClaimTypes.Scope, "scope");
options.Scope.Add("my_custom_value");

我应该实现一个自定义IProfileService包括在OnUserInformationReceived事件的范围?

当使用MVC进行oididauth时,只有IdentityToken声明被映射到claimprincipal。我无法找到映射或包含访问令牌声明到claimprincipal的方法。

我最终编写了一个授权处理程序来验证访问令牌并执行所需的声明检查。我假设你读过asp.net 5.0中的授权策略。

public class AccessTokenAuthorizationHandler : AuthorizationHandler<AccessTokenRequirement> {
readonly IOptionsMonitor<OpenIdConnectOptions> _openIdConnectOptions;
readonly ILogger<AccessTokenAuthorizationHandler> _logger;
readonly IOptions<OpenIdOptions> _openIdOptions;
public AccessTokenAuthorizationHandler(
ILogger<AccessTokenAuthorizationHandler> logger, 
IOptionsMonitor<OpenIdConnectOptions> openIdConnectOptions, 
IOptions<OpenIdOptions> openIdOptions) {
_logger = logger;
_openIdConnectOptions = openIdConnectOptions;
_openIdOptions = openIdOptions;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, AccessTokenRequirement requirement) {
if (context == null) {
throw new ArgumentNullException(nameof(context));
}
if (requirement == null) {
throw new ArgumentNullException(nameof(requirement));
}
if (context.Resource is Microsoft.AspNetCore.Mvc.ActionContext actionContext) {
ClaimsPrincipal principal = await GetAccessTokenPrincipal(actionContext.HttpContext).ConfigureAwait(false);

// verify your requirement
if (condition met) {
context.Succeed(requirement);
}
}
}
private async Task<ClaimsPrincipal> GetAccessTokenPrincipal(HttpContext httpContext) {
if (httpContext == null) {
return null;
}
String accessToken = await httpContext.GetUserAccessTokenAsync().ConfigureAwait(false);
if (!String.IsNullOrWhiteSpace(accessToken)) {
try {
TokenValidationParameters validationParameters = await BuildValidationParameters();
return new JwtSecurityTokenHandler().ValidateToken(accessToken, validationParameters, out var rawValidatedToken);

}
catch (SecurityTokenValidationException validationException) {
_logger.LogWarning(validationException, "Access token not valid.");
}
catch (Exception ex) {
_logger.LogError(ex, "Access token could not be validated.");
}
}
return null;
}
private async Task<TokenValidationParameters> BuildValidationParameters() {
var options = _openIdConnectOptions.Get(OpenIdConnectDefaults.AuthenticationScheme);
var discoveryDocument = await options.ConfigurationManager.GetConfigurationAsync(CancellationToken.None);
var signingKeys = discoveryDocument.SigningKeys;
var validationParameters = new TokenValidationParameters {
RequireExpirationTime = true,
RequireSignedTokens = true,
ValidateIssuer = true,
ValidIssuer = options.Authority,
ValidateIssuerSigningKey = true,
IssuerSigningKeys = signingKeys,
ValidateLifetime = true,
ValidateAudience = true,
ValidAudience = "your audience",
ValidateActor = false,
ValidTypes = new String[] { "at+jwt" },
ClockSkew = TimeSpan.FromMinutes(2),
};
return validationParameters;
}

}

我不高兴我不得不这样做,虽然我认为这是正确的。为了检索访问令牌,我使用nuget package IdentityModel.AspNetCore, Version=3.0.0.0 我不明白为什么没有更多的人有这个问题。当然,如果你的应用程序从你传递访问令牌的api中消费数据,那么访问令牌就变成了声明主体。但是,如果你的mvc应用程序执行直接数据库访问(并可能稍后提取到一个api),你需要以某种方式能够检查访问令牌的声明。也许我们有一些概念上的误解……

关于配置文件服务。我认为尝试将访问令牌声明包含到身份令牌中不是正确的方法。我认为这甚至是不可能的,因为当为身份令牌调用服务时,您没有关于请求范围的信息。

相关内容

  • 没有找到相关文章

最新更新