我在jwt使用React式安全。此构建可以工作,但当提供无效凭据时,它会返回json:
{
"timestamp": "2021-03-24T12:44:44.540+00:00",
"path": "/auth/login",
"status": 500,
"error": "Internal Server Error",
"message": "Invalid Credentials",
"requestId": "cfa7b741-1"
}
并在控制台中打印stacktrace:
org.springframework.security.authentication.BadCredentialsException: Invalid Credentials
at org.springframework.security.authentication.AbstractUserDetailsReactiveAuthenticationManager.lambda$authenticate$1(AbstractUserDetailsReactiveAuthenticationManager.java:99) ~[spring-security-core-5.4.5.jar:5.4.5]
以下是登录控制器:
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthAPI {
private final JwtTokenProvider tokenProvider;
private final ReactiveAuthenticationManager authenticationManager;
@PostMapping("/login")
public Mono<ResponseEntity> login(@RequestBody Mono<AuthRequest> authRequest) {
return authRequest
.flatMap(login -> authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(login.getUsername(), login.getPassword()))
.map(tokenProvider::createToken)
)
.map(jwt -> {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(HttpHeaders.AUTHORIZATION, "Bearer " + jwt);
var tokenBody = Map.of("token", jwt);
return new ResponseEntity<>(tokenBody, httpHeaders, HttpStatus.OK);
}
);
}
}
安全配置:
@Configuration
public class SecurityConfig {
@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http,
JwtTokenProvider tokenProvider,
ReactiveAuthenticationManager reactiveAuthenticationManager) {
return http
.csrf(ServerHttpSecurity.CsrfSpec::disable)
.httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
.authenticationManager(reactiveAuthenticationManager)
.securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
.authorizeExchange(it -> it
.pathMatchers("/me").authenticated()
.pathMatchers("/users/{user}/**").access(this::currentUserMatchesPath)
.anyExchange().permitAll()
)
.addFilterAt(new JwtTokenAuthenticationFilter(tokenProvider), SecurityWebFiltersOrder.HTTP_BASIC)
.build();
}
private Mono<AuthorizationDecision> currentUserMatchesPath(Mono<Authentication> authentication,
AuthorizationContext context) {
return authentication
.map(a -> context.getVariables().get("user").equals(a.getName()))
.map(AuthorizationDecision::new);
}
@Bean
public ReactiveUserDetailsService userDetailsService(UserRepository users) {
return username -> users.findByUsername(username)
.map(u -> User
.withUsername(u.getUsername()).password(u.getPasswordHash())
.authorities(u.getRoles().toArray(new String[0]))
.accountExpired(!u.getIsActive())
.credentialsExpired(!u.getIsActive())
.disabled(!u.getIsActive())
.accountLocked(!u.getIsActive())
.build()
);
}
@Bean
public ReactiveAuthenticationManager reactiveAuthenticationManager(ReactiveUserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
var authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService);
authenticationManager.setPasswordEncoder(passwordEncoder);
return authenticationManager;
}
}
jwt过滤器:
@RequiredArgsConstructor
public class JwtTokenAuthenticationFilter implements WebFilter {
public static final String HEADER_PREFIX = "Bearer ";
private final JwtTokenProvider tokenProvider;
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String token = resolveToken(exchange.getRequest());
if (StringUtils.hasText(token) && this.tokenProvider.validateToken(token)) {
Authentication authentication = this.tokenProvider.getAuthentication(token);
return chain.filter(exchange)
.contextWrite(ReactiveSecurityContextHolder.withAuthentication(authentication));
}
return chain.filter(exchange);
}
private String resolveToken(ServerHttpRequest request) {
String bearerToken = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(HEADER_PREFIX)) {
return bearerToken.substring(7);
}
return null;
}
}
我想接收正确的错误代码并编写自己的消息,但找不到配置它的方法。
我试图补充
.exceptionHandling()
.authenticationEntryPoint()
.accessDeniedHandler()
除了投手,但它不起作用。
提前谢谢!
1条答案
按热度按时间vngu2lb81#
因此,解决方案是创建新的身份验证管理器类,扩展内置的身份验证管理器类,如下所示:
在安全配置中使用它
var authenticationManager = new CustomReactiveAuthManager(userDetailsService);
或者如@toerktumlare所说,在authapi中提供令牌之前处理错误: