如何在 JWT 身份验证期间或之后设置自定义主体对象?

dis*_*ame 7 authentication spring spring-security jwt spring-boot

我更改了在后端验证用户身份的方式。从现在开始,我将从 Firebase 接收 JWT 令牌,然后在我的 Spring Boot 服务器上进行验证。

到目前为止,这工作得很好,但有一个变化我不太高兴,那就是主体对象现在是 aorg.springframework.security.oauth2.jwt.Jwt而不是 a AppUserEntity,即用户模型,就像以前一样。

// Note: "authentication" is a JwtAuthenticationToken

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Jwt jwt = (Jwt) authentication.getPrincipal();
Run Code Online (Sandbox Code Playgroud)

因此,经过一些阅读和调试后,我发现基本上像这样BearerTokenAuthenticationFilter设置对象:Authentication

// BearerTokenAuthenticationFilter.java

AuthenticationManager authenticationManager = this.authenticationManagerResolver.resolve(request);

// Note: authenticationResult is our JwtAuthenticationToken
Authentication authenticationResult = authenticationManager.authenticate(authenticationRequest);  

SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authenticationResult);
SecurityContextHolder.setContext(context);
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的,另一方面, this 来自which authenticationManageris aorg.springframework.security.authentication.ProviderManager等等。兔子洞很深。

我没有找到任何可以让我以某种方式替换Authentication.

那么计划是什么?

由于 Firebase 现在负责用户身份验证,因此可以在我的后端不知道的情况下创建用户。我不知道这是否是最好的方法,但一旦发现尚不存在的用户的有效 JWT 令牌,我打算简单地在数据库中创建一条用户记录。

此外,我的许多业务逻辑当前依赖于作为用户实体业务对象的主体。我可以更改这段代码,但这是一项乏味的工作,谁不想回顾几行遗留代码呢?

dis*_*ame 2

我的做法与朱利安·埃克卡德有点不同。

在我的WebSecurityConfigurerAdapter设置中Customizer,如下所示:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.oauth2ResourceServer()
            .jwt(new JwtResourceServerCustomizer(this.customAuthenticationProvider));
}
Run Code Online (Sandbox Code Playgroud)

customAuthenticationProviderJwtResourceServerCustomizer这样实现的:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.oauth2ResourceServer()
            .jwt(new JwtResourceServerCustomizer(this.customAuthenticationProvider));
}
Run Code Online (Sandbox Code Playgroud)

我正在NimbusJwtDecoder这样配置:

@Component
public class JwtConfig {

    @Bean
    public JwtDecoder jwtDecoder() {
        String jwkUri = "https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com";
        return NimbusJwtDecoder.withJwkSetUri(jwkUri)
                .build();
    }

}
Run Code Online (Sandbox Code Playgroud)

最后,我们需要一个自定义AuthenticationProvider来返回Authentication我们想要的对象:

public class JwtResourceServerCustomizer implements Customizer<OAuth2ResourceServerConfigurer<HttpSecurity>.JwtConfigurer> {

    private final JwtAuthenticationProvider customAuthenticationProvider;

    public JwtResourceServerCustomizer(JwtAuthenticationProvider customAuthenticationProvider) {
        this.customAuthenticationProvider = customAuthenticationProvider;
    }

    @Override
    public void customize(OAuth2ResourceServerConfigurer<HttpSecurity>.JwtConfigurer jwtConfigurer) {
        String key = UUID.randomUUID().toString();
        AnonymousAuthenticationProvider anonymousAuthenticationProvider = new AnonymousAuthenticationProvider(key);
        ProviderManager providerManager = new ProviderManager(this.customAuthenticationProvider, anonymousAuthenticationProvider);
        jwtConfigurer.authenticationManager(providerManager);
    }
}
Run Code Online (Sandbox Code Playgroud)