SecurityContext всегда имеет значение null в Spring WebFlux - PullRequest
0 голосов
/ 04 августа 2020

Я настроил Spring Webflux с JWT. Создал кастом ServerSecurityContextRepository и добавил в SecurityWebFilterChain. Но когда я получаю SecurityContext во время входящих запросов, контекст безопасности всегда возвращает 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));
            }
        }
    }
}

SecurityConfiguration.class

@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

...