自定义登录页结合UserDetailsService登录失效及控制器返回值疑问
问题排查与解决方案:自定义Spring Security登录表单不触发UserDetailsService
我来帮你梳理下问题所在,以及对应的解决办法:
一、为什么UserDetailsServiceImp没有被调用?
核心原因是你的登录请求没有进入Spring Security的认证流程:
- 你自定义的表单提交到了
/validate路径,但你自己写了一个处理该路径的控制器方法,导致请求被Spring MVC直接处理,完全跳过了Spring Security的认证逻辑,自然不会调用UserDetailsServiceImp的loadUserByUsername方法。 - 你的
WebSecurityConfig配置中,没有指定Spring Security要处理的登录请求路径(默认是/login),所以它不会拦截/validate的请求。
解决步骤:
修改Spring Security配置,让它接管
/validate的登录请求
在configure(HttpSecurity http)方法的formLogin部分,添加loginProcessingUrl("/validate"),告诉Spring Security这个路径是用来处理登录提交的:@Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/") // 自定义登录页面路径 .loginProcessingUrl("/validate") // 关键:指定表单提交的处理路径,由Spring Security处理 .usernameParameter("username") .passwordParameter("password") .defaultSuccessUrl("/welcome") .failureUrl("/?error=true") // 认证失败后跳转回登录页面,带错误标识 .permitAll() .and() .logout() .logoutUrl("/logOut") .permitAll(); }删除你自己写的
/validate控制器方法
这个请求不需要你手动处理,Spring Security会自动完成认证逻辑:成功就跳转到/welcome,失败就跳回登录页面并携带错误信息。修复UserDetailsServiceImp中的密码处理问题
你当前在loadUserByUsername中每次都对用户密码重新加密,这会导致密码比对失败(Spring Security会对前端传的密码再加密一次,相当于二次加密)。修改如下:@Component public class UserDetailsServiceImp implements UserDetailsService { private static Logger logger = LogManager.getLogger(UserDetailsServiceImp.class); // 这里要改成当前类,不是AuthService @Autowired EntityManager em; @Autowired private BCryptPasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = findUserbyUername(username); System.out.println("Called service"); UserBuilder builder = null; if (user != null) { builder = org.springframework.security.core.userdetails.User.withUsername(username); // 直接使用用户的加密密码,不要再次加密 builder.password(user.getPassword()); builder.roles(user.getRoles()); } else { throw new UsernameNotFoundException("User not found."); } return builder.build(); } private User findUserbyUername(String username) { if (username.equalsIgnoreCase("admin")) { // 提前对明文密码加密,这里直接返回加密后的结果 String encryptedPassword = passwordEncoder.encode("admin123"); return new User(username, encryptedPassword, "ADMIN"); } return null; } }
二、关于/validate路径的控制器返回值
结论是:你不需要自己写这个控制器。
Spring Security会自动处理/validate的POST请求:
- 认证成功:自动跳转到你配置的
defaultSuccessUrl("/welcome") - 认证失败:自动跳转到登录页面(你配置的
loginPage("/")),并可以通过${SPRING_SECURITY_LAST_EXCEPTION.message}获取错误信息
你可以在登录JSP中添加错误信息展示:
<c:if test="${param.error != null}"> <div class="alert alert-danger" id="message"> <strong>Error!</strong> ${SPRING_SECURITY_LAST_EXCEPTION.message} </div> </c:if>
内容的提问来源于stack exchange,提问作者amitabh pandey
相关产品推荐
相关产品推荐

