首页 > 解决方案 > Spring WebFlux 中的 SecurityContext 始终为空

问题描述

我用 JWT 配置了 Spring Webflux。创建自定义ServerSecurityContextRepository并将其添加到SecurityWebFilterChain. 但是当我在传入请求时获得 SecurityContext 时, Security context 总是返回null

以下代码是我的配置:

SecurityContextRepository.class

@Component
public class SecurityContextRepository implements ServerSecurityContextRepository {

    private static final Logger LOGGER = LoggerFactory.getLogger(SecurityContextRepository.class);
    private static final Pattern PATTERN = Pattern.compile("Bearer (.+)");

    private final JWTVerifier verifier;
    private final UserRepository userRepository;

    @SuppressFBWarnings("EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS")
    public SecurityContextRepository(
            SignatureAlgorithmProvider algorithmProvider, UserRepository userRepository) {
        this.userRepository = requireNonNull(userRepository);

        try {
            verifier = JWT.require(algorithmProvider.algorithm()).withIssuer(JwtTokenGenerator.ISSUER).build();
        } catch (Exception e) {
            throw new BeanInitializationException("Could not initialize JWT verifier", e);
        }
    }

    @Override
    public Mono<Void> save(ServerWebExchange serverWebExchange, SecurityContext securityContext) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Mono<SecurityContext> load(ServerWebExchange serverWebExchange) {
        var token = extractToken(serverWebExchange.getRequest());

        if (token == null) {
            return Mono.empty();
        } else {
            try {

                var jwt = verifier.verify(token);
                var userId = UUID.fromString(jwt.getSubject());
                var userOptional = userRepository.fetchOneById(userId);

                if (userOptional.isPresent()) {
                    var user = userOptional.get();
                    return Mono.just(new SecurityContextImpl(new JwtAuthenticationToken(securityUser, roles(user.roles()))));
                }
                return Mono.empty();
            } catch (JWTDecodeException | IllegalArgumentException e) {
                LOGGER.warn("Bearer token cannot be decoded as JWT: {}", token, e);
                return Mono.error(new UnauthorizedException("Bearer token cannot be decoded as JWT.", e));
            } catch (SignatureVerificationException e) {
                LOGGER.warn("Received access token with an invalid signature: {}", token, e);
                return Mono.error(
                        new UnauthorizedException("Received access token with an invalid signature.", e));
            } catch (TokenExpiredException e) {
                LOGGER.warn("JWT token expired.", e);
                return Mono.error(new UnauthorizedException("JWT token expired.", e));
            } catch (Exception e) {
                LOGGER.warn("Exception verifying JWT: {}", token, e);
                return Mono.error(new UnauthorizedException("Exception verifying JWT.", e));
            }
        }
    }
}

安全配置类

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfiguration {

    private final SecurityContextRepository securityContextRepository;

    @Autowired
    public SecurityConfiguration(SecurityContextRepository securityContextRepository) {
        this.securityContextRepository = requireNonNull(securityContextRepository);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @SuppressFBWarnings(value = "SPRING_CSRF_PROTECTION_DISABLED")
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
                // Disable default security.
        return http.httpBasic()
                    .disable()
                    .formLogin()
                    .disable()
                    .csrf()
                    .disable()
                    .logout()
                    .disable()
                    .cors()
                    .and()
                    // Add custom security.
                    .securityContextRepository(securityContextRepository)
                    .addFilterAt(
                            new SecurityContextServerWebExchangeWebFilter(),
                            SecurityWebFiltersOrder.SECURITY_CONTEXT_SERVER_WEB_EXCHANGE)
                    .authorizeExchange()
                    .pathMatchers("/api/authentication/v1/*", "/status", "/info", "/health", "/docs/**")
                    .permitAll()
                    .pathMatchers(HttpMethod.GET, "/api/locations/v1/**")
                    .permitAll()
                    .anyExchange()
                    .authenticated()
                    .and()
                    .exceptionHandling()
                    .and()
                    .build();
    }
}

Jwt 版本:com.auth0:java-jwt:3.10.3 SpringBoot 版本:2.3.2:RELEASE

标签: javaspring-securityjwtspring-webflux

解决方案


推荐阅读