我有一个带有 spring-boot 的 java 应用程序。我的代码开始在身份验证部分出现 StackOverFlow 错误,因此通过日志我查找问题并意识到问题出在以下行中
var 身份验证 = manager.authenticate(authenticationToken);
我将放置我尝试使这部分身份验证工作的代码
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Autowired
private SecurityFilter securityFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(req -> {
req.requestMatchers("/authentication").permitAll();
req.anyRequest().authenticated();
})
.addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Component
public class SecurityFilter extends OncePerRequestFilter {
@Autowired
private TokenService tokenService;
@Autowired
private UserRepository repository;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
var tokenJWT = recuperarToken(request);
if (tokenJWT != null) {
var subject = tokenService.getSubject(tokenJWT);
var usuario = repository.findByEmail(subject);
var authentication = new UsernamePasswordAuthenticationToken(usuario, null, usuario.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
private String recuperarToken(HttpServletRequest request) {
var authorizationHeader = request.getHeader("Authorization");
if (authorizationHeader != null) {
return authorizationHeader.replace("Bearer ", "").trim();
}
return null;
}
}
@RestController
@RequestMapping("/authentication")
public class AuthenticationController {
@Autowired
private AuthenticationManager manager;
@Autowired
private TokenService tokenService;
@PostMapping
public ResponseEntity efetuarLogin(@RequestBody @Valid UserDTO dados) {
try {
var authenticationToken = new UsernamePasswordAuthenticationToken(dados.email(), dados.password());
var authentication = manager.authenticate(authenticationToken);
System.out.println(authentication);
var tokenJWT = tokenService.gerarToken((User) authentication.getPrincipal());
return ResponseEntity.ok(new TokenJWT(tokenJWT));
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.badRequest().body(e.getMessage());
}
}
}
问题很可能是这个片段:
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
以下是定义authenticationManager的方法:
@Bean
public AuthenticationManager authenticationManager(HttpSecurity http, PasswordEncoder passwordEncode, UserDetailsService userDetailsService) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder =
http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
return authenticationManagerBuilder.build();
}
您已经定义了
PasswordEncoder
,但您可能仍然需要定义UserDetailsService
,如果还没有,它只需实现一种方法,即如何加载用户(大概从数据库):
@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByEmail(username)
.map(AppUserDetails::of)
.orElseThrow();
}
}
希望这有帮助!