我在使用新的 Spring Security 配置时遇到一些问题。我使用的是 Spring Boot 版本 3.1.4 和 Spring Security 版本 6.1.4。 在配置文件中,我定义某些页面无需身份验证即可访问。之后,我将 JwtAuthFilter 添加到链中。然而它总是被称为。即使对于应该允许的端点也是如此。例如,允许在没有身份验证的情况下访问因 403 错误而调用的错误页面。不幸的是,它还尝试通过 jwtAuthfilter 进行身份验证,这会导致另一个 403 错误,从而导致身份验证循环。我该如何解决这个问题? 这是我的配置和过滤器。
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class WebSecurityConfig {
private final JwtAuthFilter jwtAuthFilter;
private final UserProfileRepository userProfileRepository;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests(auth -> {
auth.requestMatchers("/").permitAll();
auth.requestMatchers("/login").permitAll();
auth.requestMatchers("/register").permitAll();
auth.requestMatchers("/error/**").permitAll();
})
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider())
.addFilterAfter(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
@Bean
public UserDetailsService userDetailsService() {
return username -> {
RegisteredUser registeredUser = userProfileRepository.findByMail(Email.of(username));
if (registeredUser == null) {
throw new UsernameNotFoundException("User not found");
}
return registeredUser;
};
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService());
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
public AuthenticationManager authenticationManager(UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
return authentication -> {
UserDetails user = userDetailsService.loadUserByUsername(authentication.getName());
if (passwordEncoder.matches(authentication.getCredentials().toString(), user.getPassword())) {
return new UsernamePasswordAuthenticationToken(
user.getUsername(),
user.getPassword(),
user.getAuthorities());
}
throw new BadCredentialsException("Bad Password");
};
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
} //TODO read from properties
}
这是我的过滤器
@Component
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserProfileRepository userProfileRepository;
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain) throws ServletException, IOException {
final Cookie[] cookies = request.getCookies();
if (cookies == null || cookies.length == 0) {
filterChain.doFilter(request, response);
return;
}
Optional<Cookie> authorizationCookie = Arrays.stream(cookies)
.filter(cookie -> cookie.getName().equals("Authorization"))
.findFirst();
if (authorizationCookie.isEmpty()) {
filterChain.doFilter(request, response);
return;
}
String token = authorizationCookie.get().getValue();
String mail = jwtService.extractMail(token);
if (mail == null) {
filterChain.doFilter(request, response);
return;
}
SecurityContext context = SecurityContextHolder.getContext();
if (context.getAuthentication() != null) {
filterChain.doFilter(request, response);
return;
}
RegisteredUser user = userProfileRepository.findByMail(Email.of(mail));
if (user == null) {
filterChain.doFilter(request, response);
return;
}
if (jwtService.isTokenValid(token, user)) {
var authenticationToken = new UsernamePasswordAuthenticationToken(
user,
null,
user.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
context.setAuthentication(authenticationToken);
}
filterChain.doFilter(request, response);
}
}
将为每个请求调用您的过滤器,除非且直到您使用不同的基本路由创建单独的
SecurityFilterChain
。您可以添加检查以绕过过滤器中的特定路由:
if (request.getRequestURI().contains("/login") || request.getRequestURI().contains("/register")) {
filterChain.doFilter(request, response);
}