如何使用 Webflux 在 Spring API 处理程序方法中访问 JWT 声明?

Posted

技术标签:

【中文标题】如何使用 Webflux 在 Spring API 处理程序方法中访问 JWT 声明?【英文标题】:How can I access JWT claims in Spring API handler methods using Webflux? 【发布时间】:2019-10-11 11:39:50 【问题描述】:

我正在添加一个 WebFilter 以在 SecurityWebFilterChain 内执行 JWT 身份验证。我们在 JWT 中编码了许多 API 端点所需的与身份验证无关的信息,因此我需要能够从 JWT 中提取信息并在我的 API 处理程序方法(例如 LoginController.爪哇)。实现这一目标的最佳模式是什么?

这是显示 WebFilter 身份验证的 SecurityWebFilterChain:

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) 

        return http
                .authorizeExchange()
                .pathMatchers("/login", "/")
                .authenticated()
                .and()
                .addFilterAt(basicAuthenticationFilter(), SecurityWebFiltersOrder.HTTP_BASIC)
                .authorizeExchange()
                .pathMatchers("/adm")
                .authenticated()
                .and()
                .addFilterAt(basicAuthenticationFilter(), SecurityWebFiltersOrder.HTTP_BASIC)
                .authorizeExchange()
                .pathMatchers("/api/**")
                .access(authorizationManager)
                .and()
                .addFilterAt(bearerAuthenticationFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
                .build();
    

这是我想在 LoginController.java 中访问声明的地方:

@RestController()
@RequestMapping(value = "/login")
public class LoginController 

    private final UserMongoRepository repository;

    @Autowired
    public LoginController(UserMongoRepository repository) 
        this.repository = repository;
    

    @PostMapping("")
    public Mono<User> login(@RequestBody User post,
                            @RequestParam String user_id,
                            @RequestParam String username) 

        //Need to access information from JWT claims here

        return this.repository.findById(user_id);
    

【问题讨论】:

【参考方案1】:

我会创建一个自定义的Authentication 对象并将所需的信息存储在其中。

对于用户相关的数据,存储在其Principal中。对于非用户相关的数据,听起来Details是一个存储的好地方。

许多内置的AuthenticationProvider 将创建一个UserDetails 并存储到Principal。这意味着如果您使用的是内置的AuthenticationProvider,则可以考虑创建一个定制的UserDetails

所以根据你实现认证逻辑的方式,你需要自定义相关的AuthenticationProviderFilter等。目的是访问HttpServletRequest,从HTTP头中获取JWT,解析JWT,设置并配置这个自定义的Authentication 对象并将其设置为SecurityContext

SecurityContextHolder.getContext().setAuthentication(authenication);

要在 Controller 中访问这个 Authentication 对象,您可以使用:

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
CurrentUser user = (CurrentUser) auth.getPrincipal();
CurrentRequestDetail detail= (CurrentRequestDetail) auth.getDetails();
/** CurrentUser and CurrentRequestDetail is the customised Principal and Details**/

如果你只需要访问[Principal],你可以使用@AuthenticationPrincipal

    @PostMapping("")
    public Mono<User> login(@RequestBody User post,
                            @RequestParam String user_id,
                            @RequestParam String username,
                            @AuthenticationPrincipal CurrentUser currentUser) 

        //Need to access information from JWT claims here

        return this.repository.findById(user_id);
    

【讨论】:

以上是关于如何使用 Webflux 在 Spring API 处理程序方法中访问 JWT 声明?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 spring webflux 读取请求正文

覆盖 Spring webflux 项目的默认 Threadpool 执行器的效果如何?

如何在Spring WebFlux中记录请求和响应主体

在没有 servlet api 的 webflux 项目中使用 OAuth2 和 Spring Security OAuth2 和 reactor netty

Spring Boot Webflux 反应式 API

如何模拟 Spring WebFlux WebClient?