【问题标题】:Manually validating a token from an OIDC provider without `well-known` metadata in Asp Net Core 3.1在 Asp Net Core 3.1 中手动验证来自 OIDC 提供程序的令牌,而没有“众所周知的”元数据
【发布时间】:2021-11-15 11:25:01
【问题描述】:

我正在使用带有 Openid 的流程,在该流程中我将用户重定向到另一个提供商,以处理登录问题,并且在此登录后,我在 /login/callback?code=xxxx URL 中收到 code

所以,JWT 是使用 code 生成的,但我无法验证它。我的 STS 中没有well-known 端点,我需要这样手动配置:

    services.AddAuthorization(cfg =>
        {
            cfg.AddPolicy("MyPolicy", cfgPolicy =>
            {
                cfgPolicy.AddRequirements().RequireAuthenticatedUser();
                cfgPolicy.AddAuthenticationSchemes(OpenIdConnectDefaults.AuthenticationScheme);
            });
        }).AddAuthentication(cfg =>
        {
            cfg.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            cfg.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect(cfg =>
        {
            cfg.ClientId = authenticationConfig.ClientId;
            cfg.ClientSecret = authenticationConfig.ClientSecret;
            cfg.ResponseType = "code";
            cfg.CallbackPath = "/login/callback";
            cfg.Scope.Clear();
            cfg.Scope.Add("openid");
            
            cfg.TokenValidationParameters = new TokenValidationParameters
            {
                ValidIssuer = "https://myissuer"
            };

            cfg.Configuration = new OpenIdConnectConfiguration
            {
                AuthorizationEndpoint = "https://mysts/api/oauth/authorize",
                TokenEndpoint = "https://mysts/api/oauth/token",
                UserInfoEndpoint = "https://mysts/api/oauth/token_info"
            };
        });

一些要点:

  1. 我有一个令牌自检端点,用于验证我的令牌(token_info 端点)。
  2. 我没有返回公钥 (jwks) 的默认端点。我的端点始终是某些值的连接,例如 --> https://mysts/offline/jwks/{kid}/{clientid},所以这是动态的并且取决于令牌。
  3. 我没有众所周知的端点。

【问题讨论】:

  • 您能告诉我您的问题吗?你想让我们帮你什么?
  • “我有一个令牌自省端点”,您还可以将每个令牌提交到自省端点进行验证,这可能更容易实现,但最终速度较慢执行条款(考虑到它是异步同步和所有这些)。

标签: asp.net-core oauth-2.0 openid-connect openid


【解决方案1】:

您无法验证它,因为 ASP.NET Core 默认尝试验证 JWT 签名。但是,由于您自己设置了元数据,并且没有给出JwksUri,因此它无法获取 OIDC 提供者的公钥来验证签名。

您可以指定JwksUri,或关闭签名验证(不安全),或自行验证。如果您有权访问公钥,请以某种方式使用options.SecurityTokenValidator 并实现ISecurityTokenValidator 进行自定义验证。

这是一个(未经测试)动态获取 JWKS 并验证令牌的实现:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication()
        .AddOpenIdConnect(options => {
            options.SecurityTokenValidator = new MyJwtValidator(Configuration);
        });
}

class MyJwtValidator: ISecurityTokenValidator
{
    private readonly IConfiguration _configuration;
    private readonly HttpClient _httpClient;
    private readonly JwtSecurityTokenHandler _tokenHandler;

    public MyJwtValidator(IConfiguration configuration)
    {
        _configuration = configuration;
        _tokenHandler = new JwtSecurityTokenHandler();
        _httpClient = new HttpClient
        {
            BaseAddress = new Uri(_configuration.GetSection("OidcProvider").Get<string>())
        };
    }

    public bool CanReadToken(string securityToken) => true;

    public ClaimsPrincipal ValidateToken(
        string securityToken,
        TokenValidationParameters validationParameters,
        out SecurityToken validatedToken
    )
    {
        // parse the token (without validating) to extract a value
        var parsedToken = new JwtSecurityToken(securityToken);
        var keyId = parsedToken.Claims.First(c => c.Type == "kid").Value;
        
        // fetch JWKS and validate the token
        var clientId = _configuration.GetSection("OidcProvider:ClientId").Get<string>();
        var jwks = _httpClient.GetStringAsync($"url/to/jwks/{keyId}/{clientId}").Result;
        // jwks == "{ keys: [..."
        var signingKeys = new JsonWebKeySet(jwks).GetSigningKeys();

        return _tokenHandler.ValidateToken(securityToken, new TokenValidationParameters
        {
            IssuerSigningKeys = signingKeys
        }, out validatedToken);
    }

    public bool CanValidateToken { get; } = true;
    public int MaximumTokenSizeInBytes { get; set; } = int.MaxValue;
}

它正在执行异步同步,这是不受欢迎的,但您可能希望缓存密钥以避免支付罚款。

【讨论】:

  • 谢谢,我将使用这个解决方案来制作我自己的验证令牌。
猜你喜欢
  • 2021-11-14
  • 1970-01-01
  • 1970-01-01
  • 2014-06-14
  • 1970-01-01
  • 1970-01-01
  • 2021-11-05
  • 2019-09-26
  • 2020-09-21
相关资源
最近更新 更多