在每个请求上验证 OpenId IdToken

Validating OpenId IdToken On Each Request

我尝试验证每次请求时从 Azure AD 获得的 IdToken,但我一直收到错误消息,指出令牌上没有签名。当我验证访问令牌时它可以工作,但我宁愿使用包含用户声明的 Id 令牌。有没有办法让 Azure 也发回带有签名的 Id 令牌?

public JwtSecurityToken ValidateJwtToken(string jwtToken)
    {
        string stsDiscoveryEndpoint = $"{_authority}/.well-known/openid-configuration";

       ConfigurationManager<OpenIdConnectConfiguration> configManager =
            new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());

       OpenIdConnectConfiguration config = configManager.GetConfigurationAsync().Result;

       TokenValidationParameters validationParameters = new TokenValidationParameters
        {
            ValidateAudience = false,
            ValidateIssuer = false,
            ValidateLifetime = false,
            IssuerSigningKeys = config.SigningKeys
        };

       JwtSecurityTokenHandler tokendHandler = new JwtSecurityTokenHandler();

       try
        {
            SecurityToken token;
            tokendHandler.ValidateToken(jwtToken, validationParameters, out token);

           return token as JwtSecurityToken;
        }
        catch (Exception ex)
        {
            loggingService.LogError("Could not validate azure ad token", nameof(AzureSecurityService), ex);
            return null;
        }
    }

   public async Task<string> GenerateToken(string code)
    {
        AuthenticationContext authenticationContext = new AuthenticationContext(_authority);

       try
        {
            string baseUrl = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);
            AuthenticationResult result =
                await authenticationContext.AcquireTokenByAuthorizationCodeAsync(code, new Uri(baseUrl), new ClientCredential(_clientId, _clientSecret));

           return result.IdToken;
        }
        catch (AdalException adalex)
        {
            loggingService.LogError("Could not get authorization request url", nameof(AzureSecurityService), adalex);
            return null;
        }
        catch (Exception ex)
        {
            loggingService.LogError("Could not get authorization request url", nameof(AzureSecurityService), ex);
            return null;
        }
    }

   public async Task<string> GetAuthUrl()
    {
        AuthenticationContext authenticationContext = new AuthenticationContext(_authority);

       // Config for OAuth client credentials  
       try
        {
            string baseUrl = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);
            var authUri =
                await authenticationContext.GetAuthorizationRequestUrlAsync("00000000-0000-0000-0000-000000000000", _clientId, new Uri(baseUrl), UserIdentifier.AnyUser, null);

           return authUri.ToString();
        }
        catch (AdalException adalex)
        {
            loggingService.LogError("Could not get authorization request url", nameof(AzureSecurityService), adalex);
            return null;
        }
        catch (Exception ex)
        {
            loggingService.LogError("Could not get authorization request url", nameof(AzureSecurityService), ex);
            return null;
        }
    }

更新

因此,无论出于何种原因,即使没有提供范围,我也会收回索赔。我现在所做的只是将查询参数添加到 auth url 范围并请求 openid 和 profile:

var authUri =
                await authenticationContext.GetAuthorizationRequestUrlAsync("00000000-0000-0000-0000-000000000000", _clientId, new Uri(GetBaseUrl()), UserIdentifier.AnyUser, "scope=openid profile");

我现在的问题是为什么默认作用域不是 return 带有签名的 id_token?

您应该忘记在您的授权请求中输入所需的范围值,

来自 OpenID Connect specification

Scope

REQUIRED. OpenID Connect requests MUST contain the openid scope value. If the openid scope value is not present, the behavior is entirely unspecified. Other scope values MAY be present. Scope values used that are not understood by an implementation SHOULD be ignored. See Sections 5.4 and 11 for additional scope values defined by this specification.

所以必须在授权请求中指定openid

并且 Azure return OAuth 2.0 令牌响应的 ID 令牌(当 openid 范围不存在时)。

来自 Azure AD OAuth2.0 documentation,

id_token

An unsigned JSON Web Token (JWT). The app can base64Url decode the segments of this token to request information about the user who signed in. The app can cache the values and display them, but it should not rely on them for any authorization or security boundaries.

正如文档所说,它只是为了向最终用户显示。不得将此 ID 令牌用于 authenticate/authorize.

另一方面,为了获得正确的 OpenID Connect 令牌响应,Auzre 会向您发送一个已签名的 ID 令牌,

来自documentation

id_token

The id_token that the app requested. You can use the id_token to verify the user's identity and begin a session with the user.

验证同一文档的 id_token 部分解释了如何验证令牌

希望这能解决您的问题。