![](/img/trans.png)
[英]How to check access token only if resource is secured in spring security?
[英]How to ensure only JWT tokens from own application are accepted in Spring Security secured resource server
I am using Spring Security with Spring Boot 2.2.0, trying to get Azure AD B2C working, using spring-security-oauth2-resource-server:5.2.0
and spring-security-oauth2-jose:5.2.0
.
使用此配置:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**")
.authenticated()
.and()
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
}
}
在我的application.properties
中设置了spring.security.oauth2.resourceserver.jwt.jwk-set-uri
。
我可以从 Azure AD B2C 获取令牌,并使用该令牌访问我自己的 API 端点。 但是,如果我使用另一个目录中的令牌,也可以访问端点。
我确实在委托人的声明中看到这来自另一个 azure 目录。 这是我需要在我的应用程序中手动添加的东西吗(测试应用程序 ID 是否与声明中的匹配)? 或者我应该添加一些我还没有完成的其他配置?
我还尝试使用JwtDecoders.fromOidcIssuerLocation("https://mycompb2ctestorg.b2clogin.com/mycompb2ctestorg.onmicrosoft.com/v2.0/?p=B2C_1_ropc_flow");
添加我自己的 JwtDecoder bean ,但这给出了:
java.lang.IllegalStateException: The Issuer "https://mycompb2ctestorg.b2clogin.com/60780907-bc3a-469a-82d1-b89ffed655af/v2.0/"
provided in the configuration did not match the requested issuer
"https://mycompb2ctestorg.b2clogin.com/mycompb2ctestorg.onmicrosoft.com/v2.0/?p=B2C_1_ropc_flow"
此外,使用:
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://mycompb2ctestorg.b2clogin.com/mycompb2ctestorg.onmicrosoft.com/v2.0/?p=B2C_1_ropc_flow
给出与尝试声明我自己的JwtDecoder
bean 相同的异常。
在阅读了 Spring 安全文档中的自定义令牌验证器之后,我添加了一个自定义验证器,用于检查受众声明以确保为我自己的应用程序颁发了令牌。 为此,请创建此验证器 class:
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));
}
}
}
并通过在WebSecurityConfigurerAdapter
配置 class 中声明自己的JwtDecoder
bean 来使用它:
@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
的构造函数中
我知道我迟到了,但当前答案中缺少一些信息。
非法状态异常:
provided in the configuration did not match the requested issuer
很可能是因为@Dragana Le Mitova 在 issue-uri 属性末尾的斜线已经提到过。 这需要设置为:
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://mycompb2ctestorg.b2clogin.com/mycompb2ctestorg.onmicrosoft.com/v2.0
Spring will then pull the configuration for the OAuth Resource Server from https://mycompb2ctestorg.b2clogin.com/mycompb2ctestorg.onmicrosoft.com/v2.0/.well-known/openid-configuration
automatically.
为确保我们只接受来自 Azure 应用程序的 JWT,我们需要检查 JWT 的受众 (aud) 属性。 对于 Azure 应用程序,这通常与客户端/应用程序 ID 相同。 正如@Wim Deblauwe 已经回答的那样,这是通过JwtDecoder
的自定义验证器完成的。 Spring Security 甚至在他们的文档中为我们提供了一个自定义 JWT 验证器的示例,他们在其中实施了受众声明检查。 这是通过在JwtDecoder
bean 中提供我们自己的验证器来完成的。
受众 (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 在设置 issue-uri 属性时的默认行为。
如果您想更深入地了解 go,我们目前必须添加自定义验证器的方式是否最佳,目前 正在进行讨论。
我怀疑您在尝试声明自己的JwtDecoder束时遇到的异常来自缺少的斜线。
请注意,“请求的颁发者”总是缺少尾部斜杠,即使在配置中明确指定了尾部斜杠。
Spring 按照规范的要求,安全性会在附加之前从颁发者 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
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.