3 回答
TA贡献1848条经验 获得超6个赞
我知道我参加聚会迟到了,但当前答案中缺少一些信息。
非法状态异常:
provided in the configuration did not match the requested issuer
很可能是由于 @Dragana Le Mitova 已经在 issues-uri 属性末尾的斜线提到的那样引起的。这需要设置为:
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://mycompb2ctestorg.b2clogin.com/mycompb2ctestorg.onmicrosoft.com/v2.0
然后 Spring 将自动提取 OAuth 资源服务器的配置https://mycompb2ctestorg.b2clogin.com/mycompb2ctestorg.onmicrosoft.com/v2.0/.well-known/openid-configuration。
为了确保我们只接受来自 Azure 应用程序的 JWT,我们需要检查 JWT 的受众 (aud) 属性。对于 Azure 应用程序,这通常与客户端/应用程序 ID 相同。正如 @Wim Deblauwe 已经回答的那样,这是通过JwtDecoder. Spring Security 甚至在他们的文档中为我们提供了一个自定义 JWT 验证器的示例,其中他们实现了受众声明检查。这是通过在JwtDecoderbean 中提供我们自己的验证器来完成的。
受众(aud)声明验证器:
public class AudienceValidator implements OAuth2TokenValidator<Jwt> {
OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null);
public OAuth2TokenValidatorResult validate(Jwt jwt) {
if (jwt.getAudience().contains("messaging")) {
return OAuth2TokenValidatorResult.success();
} else {
return OAuth2TokenValidatorResult.failure(error);
}
}
}
Jwt解码器:
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoderJwkSupport jwtDecoder = (NimbusJwtDecoderJwkSupport)
JwtDecoders.withOidcIssuerLocation(issuerUri);
OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator();
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);
jwtDecoder.setJwtValidator(withAudience);
return jwtDecoder;
}
这与 @Wim Deblauwe 提供的答案略有不同,我们使用JwtValidators.createDefaultWithIssuer(issuerUri)而不是创建验证器JwtValidators.createDefault()。这很重要,因为我们本质上要检查 3 个 JWT 属性:
到期日
发行人
观众
我们JwtValidators.createDefault()只为过期属性创建一个验证器。我们为JwtValidators.createDefaultWithIssuer(issuerUri)过期和发行者属性创建验证器。JwtValidators.createDefaultWithIssuer(issuerUri)也是 Spring Security 设置 issues-uri 属性时的默认行为。
如果您想更深入地了解,我们目前添加自定义验证器的方式是否是最佳方式正在进行讨论。
TA贡献1799条经验 获得超8个赞
在阅读了Spring Security 文档中的自定义令牌验证器后,我添加了一个自定义验证器来检查受众声明,以确保令牌是为我自己的应用程序颁发的。为此,请创建此验证器类:
private static class AudienceValidator implements OAuth2TokenValidator<Jwt> {
@Override
public OAuth2TokenValidatorResult validate(Jwt token) {
if (token.getAudience().contains("my-application-id-here")) {
return OAuth2TokenValidatorResult.success();
} else {
return OAuth2TokenValidatorResult.failure(
new OAuth2Error("invalid_token", "The audience is not as expected, got " + token.getAudience(),
null));
}
}
}
并通过JwtDecoder在配置类中声明您自己的 bean来使用它WebSecurityConfigurerAdapter:
@Bean
public JwtDecoder jwtDecoder() {
NimbusJwtDecoder result = NimbusJwtDecoder.withJwkSetUri(properties.getJwt().getJwkSetUri()).build();
result.setJwtValidator(
new DelegatingOAuth2TokenValidator<Jwt>(
JwtValidators.createDefault(),
new AudienceValidator())
);
return result;
}
默认验证器将检查时间戳等内容。如果没问题,AudienceValidator 将检查受众声明。
注意:您在验证器中传递的顺序DelegatingOAuth2TokenValidator定义了 JWT 令牌的检查顺序。在此示例中,在观众之前检查时间戳。如果你想让观众先检查,你需要把它放在构造函数的前面DelegatingOAuth2TokenValidator
TA贡献1815条经验 获得超10个赞
我怀疑您在尝试声明自己的JwtDecoder光束时遇到的异常来自缺少的斜杠。
请注意,“请求的发行者”始终缺少尾部斜杠,即使在配置中明确指定了尾部斜杠。
按照规范的要求, Spring Security在附加之前会从颁发者 URI 中删除所有尾部斜杠。但是,在获取配置后,返回的配置的颁发者 URI 与问题 URI 的“清理”版本相匹配,而不是最初提供的版本。
由于fromOidcIssuerLocation()不知道最初提供的颁发者 URL,因此它会与 cleanIssuer 进行匹配,从而导致所描述的问题。解决这个问题的最简单方法是在fromOidcIssuerLocation()中进行清理,然后仍然可以使用原始版本进行匹配。
另一条注释与您提出的第一个问题相关。
如果我知道您的 API 标识符 + 您的租户 ID,我可以使用客户端凭据获取您的 API 的访问令牌!令牌不会包含范围或角色,它不能。因此,检查是否存在有效的委派权限(也称为范围)或有效的应用程序权限(在角色声明中)至关重要。
看看这个特定的代码。
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = new TokenValidationParameters
{
// We accept both the App Id URI and the AppId of this service application
ValidAudiences = new[] { audience, clientId },
// Supports both the Azure AD V1 and V2 endpoint
ValidIssuers = new[] { issuer, $"{issuer}/v2.0" },
IssuerSigningKeys = signingKeys
};
添加回答
举报