Spring Security返回200,而不是HttpWebHandlerAdapter所说的401



试图弄清楚我是否刚刚在Spring Security中发现了一个错误,这是针对最新的2.4.5版本的。HttpWebHandlerAdapter声明它在日志中返回401,但Postman中的响应是200。以下是相关的弹簧安全配置/处理程序等。

Spring Security配置

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity(proxyTargetClass = true)
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthenticationConverter jwtAuthenticationConverter;
private final UsersRepository usersRepository;
private final UserRolesRepository userRolesRepository;
private final RoleScopesRepository roleScopesRepository;
private final JwtUtil jwtUtil;
private static Map<HttpMethod, String[]> AUTH_WHITELIST =
Map.of(
// Public auth endpoints
HttpMethod.PUT, new String[] {"/v1/auth/login"},
HttpMethod.POST, new String[] {"/v1/auth/register"},
HttpMethod.GET,
new String[] {
// Actuator
"/actuator",
"/actuator/health*",
"/actuator/info",
// SpringFox/OpenAPI
"/v3/api-docs/**",
"/swagger-ui/**",
"/swagger-resources/**",
"/webjars/swagger-ui/**",
// Public API endpoints
"/v1/posts/*/comments/*",
"/v1/posts/*/comments",
"/v1/posts/*",
"/v1/posts"
});
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
// Build path/verb matchers
Set<ServerWebExchangeMatcher> matchers = new HashSet<>();
AUTH_WHITELIST.forEach(
(method, paths) -> matchers.add(ServerWebExchangeMatchers.pathMatchers(method, paths)));
ServerWebExchangeMatcher[] matchersArray = matchers.toArray(new ServerWebExchangeMatcher[0]);
return http.addFilterAt(
getAuthenticationWebFilter(matchersArray), SecurityWebFiltersOrder.AUTHENTICATION)
.authorizeExchange()
.matchers(matchersArray)
.permitAll()
.anyExchange()
.authenticated()
.and()
.formLogin()
.and()
.csrf()
.disable()
.cors()
.configurationSource(createCorsConfigSource())
.and()
.formLogin()
.disable()
.httpBasic()
.disable()
.logout()
.disable()
.build();
}
public CorsConfigurationSource createCorsConfigSource() {
org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:3000");
config.setAllowedMethods(List.of("OPTIONS", "GET", "PUT", "POST", "DELETE"));
source.registerCorsConfiguration("/**", config);
return source;
}
private AuthenticationWebFilter getAuthenticationWebFilter(
ServerWebExchangeMatcher[] matchersArray) {
// Create web filter with custom user details service/authentication manager
AuthenticationWebFilter authenticationWebFilter =
new AuthenticationWebFilter(new AuthenticationManager(customUserDetailsService()));
// Set custom JWT authentication converter
authenticationWebFilter.setServerAuthenticationConverter(jwtAuthenticationConverter);
// Negate whitelist to set paths with required authentication
NegatedServerWebExchangeMatcher negateWhiteList =
new NegatedServerWebExchangeMatcher(ServerWebExchangeMatchers.matchers(matchersArray));
authenticationWebFilter.setRequiresAuthenticationMatcher(negateWhiteList);
// Add failure handler
authenticationWebFilter.setAuthenticationFailureHandler(new AuthenticationFailureHandler());
return authenticationWebFilter;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Primary
public UserDetailsService customUserDetailsService() {
return new UserDetailsService(
new UserService(
usersRepository,
userRolesRepository,
roleScopesRepository,
passwordEncoder(),
jwtUtil));
}
}

故障处理程序

@Slf4j
public class AuthenticationFailureHandler implements ServerAuthenticationFailureHandler {
@Override
public Mono<Void> onAuthenticationFailure(
WebFilterExchange webFilterExchange, AuthenticationException exception) {
log.warn(exception.getMessage());
ServerHttpResponse response = webFilterExchange.getExchange().getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().addIfAbsent(HttpHeaders.LOCATION, "/");
response.setComplete();
return Mono.error(exception);
}
}

JWT身份验证转换器。

@Slf4j
@RequiredArgsConstructor
@Component
public class JwtAuthenticationConverter implements ServerAuthenticationConverter {
private final JwtUtil jwtUtil;
private Mono<String> extractJwtFromAuthorizationHeader(ServerWebExchange exchange) {
return Mono.justOrEmpty(exchange.getRequest().getHeaders().get(HttpHeaders.AUTHORIZATION))
// Remove empty headers/headers with empty string as value
.filter(
header ->
!header.isEmpty()
&& StringUtils.hasText(header.get(0))
&& header.get(0).contains("Bearer"))
.map(header -> header.get(0).replaceAll(AuthConstants.BEARER_PREFIX_REGEX, ""))
.switchIfEmpty(Mono.error(new InvalidJwtException("Invalid bearer token")));
}
@Override
public Mono<Authentication> convert(ServerWebExchange exchange) {
return Mono.justOrEmpty(exchange)
.flatMap(this::extractJwtFromAuthorizationHeader)
.map(jwtUtil::getAuthenticationFromJwt);
}
}

身份验证管理器

public class AuthenticationManager extends UserDetailsRepositoryReactiveAuthenticationManager {
public AuthenticationManager(ReactiveUserDetailsService userDetailsService) {
super(userDetailsService);
}
@Override
public Mono<Authentication> authenticate(Authentication authentication) {
return authentication.isAuthenticated()
? Mono.just(authentication)
: super.authenticate(authentication);
}
}

相关日志

2021-05-05 15:41:18.981 DEBUG 1984531 --- [or-http-epoll-3] o.s.w.s.h.ResponseStatusExceptionHandler : [82168f6e-13] Resolved [InvalidJwtException: Unsupported JWT token: The parsed JWT indicates it was signed with the HS512 signature algorithm, but the specified signing key of type sun.security.rsa.RSAPublicKeyImpl may not be used to validate HS512 signatures.  Because the specified signing key reflects a specific and expected algorithm, and the JWT does not reflect this algorithm, it is likely that the JWT was not expected and therefore should not be trusted.  Another possibility is that the parser was configured with the incorrect signing key, but this cannot be assumed for security reasons.] for HTTP POST /v1/posts
2021-05-05 15:41:18.981 DEBUG 1984531 --- [or-http-epoll-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [82168f6e-13] Completed 401 UNAUTHORIZED

这不是一个错误,故障处理程序上的setComplete((是一个错误行。不再有200,日志显示为401。

相关内容

  • 没有找到相关文章

最新更新