当我在 loadUserByUsername 方法中抛出自定义异常 (AccountNotActivatedException) 时,Spring 将其包装在 InternalAuthenticationServiceException 中。一般来说,该方法中几乎所有的异常都会被封装到其中。 问题是这样的异常不能使用@ExceptionHandler(或任何其他,因为它包装了所有异常)来处理,并且它有自己的行为。 我需要准确了解用户在身份验证过程中遇到的错误,以便将其显示在视图上。 每种情况都应该有自己的错误文本,以向用户指示到底出了什么问题。
现在,据我了解,如果出现错误,它只是将“error”参数传递给请求并返回登录页面,我无法再与其交互。
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
User user = userRepository.findByUsername(username);
if(user==null){
throw new UsernameNotFoundException("Unable to login. The email or password is incorrect");
}
if (!user.isEnabled()) {
throw new AccountNotActivatedException(
"This account is not activated. " +
"To complete the registration, follow the link in the letter that was sent to your email address. " +
"We also recommend you check the \"Spam\" category."
);
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
user.isEnabled(),
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
Collections.singleton(user.getRole()));
}
这是我的 Spring 配置
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.anonymous(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(PathRequest
.toStaticResources()
.atCommonLocations())
.permitAll()
.requestMatchers("/book/{bookId}/testResults")
.authenticated()
.anyRequest().permitAll())
.formLogin(login ->login
.loginPage("/login")
.defaultSuccessUrl("/")
.permitAll())
.logout(logout ->logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll());
/*.oauth2Login( oauth2->oauth2
.loginPage("/login"));*/
/* .defaultSuccessUrl("/")
.userInfoEndpoint(userInfo-> userInfo
.oidcUserService(oidcUserService())));*/
return http.build();
}
附注我还想问一下,Spring 本身是否真的在没有我的情况下检查登录名/密码,还是我应该自己检查,接受表单中的数据并访问数据库并使用控制器方法检查此数据。 现在我只是使用 Post 方法将信息传输到 /login 端点,并且没有针对此资源的 PostMapping
我更改了此处理程序的行为,一切都按预期工作,但我不确定安全性。这有多允许和安全?
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
String errorMessage = determineErrorMessage(exception);
redirectStrategy.sendRedirect(request, response, "/login?error=" + errorMessage);
}
private String determineErrorMessage(AuthenticationException exception) {
if (exception instanceof DisabledException) {
return "This account is not activated. " +
"To complete the registration, follow the link in the letter that was sent to your email address. " +
"We also recommend checking the 'Spam' category.";
} else if (exception instanceof BadCredentialsException) {
return "Invalid username or password.";
} else {
return "Authentication failed: " + exception.getMessage();
}
}
}
@GetMapping("/login")
public String loginPage(@RequestParam(name = "error", required = false) String error, Model model) {
if (error != null) {
model.addAttribute("errorMessage", error);
}
return "login-page";
}