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

Alt*_*ltJ 5 java spring spring-security spring-security-oauth2 spring-webflux

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

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

    @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();
    }
Run Code Online (Sandbox Code Playgroud)

这是我想在 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Ken*_*han 1

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

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

许多内置函数AuthenticationProvider会创建一个UserDetails并存储到Principal. UserDetails这意味着如果您正在使用那些内置的,您可以考虑创建一个定制的AuthenticationProvider

因此,根据您如何实现身份验证逻辑,您需要自定义相关AuthenticationProviderFilter。目的是访问HttpServletRequest,从HTTP标头获取JWT,解析JWT,设置和配置这个自定义Authentication对象并将其设置为SecurityContext

SecurityContextHolder.getContext().setAuthentication(authenication);
Run Code Online (Sandbox Code Playgroud)

要在 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**/
Run Code Online (Sandbox Code Playgroud)

如果您只需要访问[ 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);
    }
Run Code Online (Sandbox Code Playgroud)