我们有一个项目,我们有:
+------------------------------------+
| | 1. gets the token
| Authorization Server (Auth) | <------------------+
| - spring-security-oauth2:2.0.14 | |
| | |
+------------------------------------+ +
user
+
+------------------------------------+ |
| | 2. uses the token |
| Resource Server (RS) | to access resourcs|
| - spring-security-oauth2:5.1.0 | <------------------+
| |
+------------------------------------+我们一直在一个没有Webflux的环境中工作,而且一切都如期而至。值得一提的是,这个JWT有以下声明: exp、user_name、authorities、jti、client_id、scope。
所有资源都有一个额外的变量:
@GetMapping("/{id}/car")
public SomeDto someResourceMethod(@PathVariable("id") CarId carId, Principal principal)Principal被实例化为OAuth2Authentication,并且在其中有操作getName。Principal被实例化为JwtAuthenticationToken,我们现在有了getSubject操作,但是它是空的,因为Claimsub是空的。你觉得我们该怎么处理这个?创建一个新的JwtDecoder?我们使用Spring5.1,解码器是NimbusReactiveJwtDecoder。
发布于 2018-09-06 18:30:23
此时,Reactive根据RFC 7519支持JWT声明,这就是您看到行为更改的原因。
是的,您可以创建自己的解码器,这可能是侵入性最小的方法:
public class CustomDecoder implements ReactiveJwtDecoder {
private final ReactiveJwtDecoder nimbus;
// ...
public Mono<Jwt> decode(String token) {
return this.nimbus.decode(token)
.map(this::mapJwt);
}
private Jwt mapJwt(Jwt jwt) {
Map<String, Object> claims = jwt.getClaims();
// ... map claims accordingly
return new Jwt(...);
}
}您还可以自定义身份验证管理器,即在RC2中介绍。
public class CustomReactiveAuthenticationManager
implements ReactiveAuthenticationManager {
private final ReactiveAuthenticationManager delegate;
// ...
public Mono<Authentication> authenticate(Authentication authentication) {
return this.delegate.authenticate(authentication)
.map(this::mapAuthentication);
}
private Authentication mapAuthentication(Authentication authentication) {
// ... create a custom authentication where getName does what you need
}
}或者,如果您能够对方法签名进行一些重构,那么另一个选项是使用@AuthenticatedPrincipal。
@GetMapping("/{id}/car")
public SomeDto someResourceMethod(
@PathVariable("id") CarId carId,
@AuthenticatedPrincipal Jwt jwt) {
String name = jwt.getClaims().get("user_name");
// ...
}或者更简洁一些
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@AuthenticationPrincipal(expression = "getClaims().get('user_name')")
public @interface CurrentUsername {}
@GetMapping("/{id}/car")
public SomeDto someResourceMethod(
@PathVariable("id") CarId carId,
@CurrentUsername String name) {
// ...
}您还可以考虑在弹簧安全上记录增强,以考虑使用户属性名称可配置。
编辑:我更新了EL表达式,因为默认情况下,@AuthenticatedPrincipal首先调用authentication.getPrincipal()。
UPDATE:在Security 5.4+中,包含主体名称的声明是可配置的,如下所示:
@Bean
JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter authenticationConverter =
new JwtAuthenticationConverter();
authenticationConverter.setPrincipalClaimName("user_name");
return authenticationConverter;
}然后,它允许OP与其他主体类型一样使用Principal#getName。
https://stackoverflow.com/questions/52186005
复制相似问题