首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring + JWT Oauth2: Spring 5 vs Spring <5

Spring + JWT Oauth2: Spring 5 vs Spring <5
EN

Stack Overflow用户
提问于 2018-09-05 13:11:26
回答 1查看 2.7K关注 0票数 2

我们有一个项目,我们有:

代码语言:javascript
复制
+------------------------------------+
|                                    |    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。

所有资源都有一个额外的变量:

代码语言:javascript
复制
@GetMapping("/{id}/car")
public SomeDto someResourceMethod(@PathVariable("id") CarId carId, Principal principal)
  • "Spring“(不使用反应堆)中:Principal被实例化为OAuth2Authentication,并且在其中有操作getName
  • "Spring“(使用反应堆)中:Principal被实例化为JwtAuthenticationToken,我们现在有了getSubject操作,但是它是空的,因为Claimsub是空的。

你觉得我们该怎么处理这个?创建一个新的JwtDecoder?我们使用Spring5.1,解码器是NimbusReactiveJwtDecoder

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-06 18:30:23

此时,Reactive根据RFC 7519支持JWT声明,这就是您看到行为更改的原因。

是的,您可以创建自己的解码器,这可能是侵入性最小的方法:

代码语言:javascript
复制
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中介绍

代码语言:javascript
复制
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

代码语言:javascript
复制
@GetMapping("/{id}/car")
public SomeDto someResourceMethod(
    @PathVariable("id") CarId carId,
    @AuthenticatedPrincipal Jwt jwt) {

    String name = jwt.getClaims().get("user_name");
    // ...
}

或者更简洁一些

代码语言:javascript
复制
@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+中,包含主体名称的声明是可配置的,如下所示:

代码语言:javascript
复制
@Bean
JwtAuthenticationConverter jwtAuthenticationConverter() {
    JwtAuthenticationConverter authenticationConverter =
        new JwtAuthenticationConverter();
    authenticationConverter.setPrincipalClaimName("user_name");
    return authenticationConverter;
}

然后,它允许OP与其他主体类型一样使用Principal#getName

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52186005

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档