Spring Security中LoginBean认证方法未调用及UserDetails去向咨询
解决Spring Security + JSF/PrimeFaces登录的两个问题
Hey there! Let's tackle your issues one by one—this is a common pitfall when mixing Spring Security with JSF, so you're not alone.
问题1:LoginBean的认证方法始终未被调用
First off, let's clarify how Spring Security's form login works with JSF: Spring Security takes over the authentication flow, so you don't need to call a bean method directly from your login form. Here's why your bean method isn't firing, and how to fix it:
常见原因&解决方案
- 错误的表单提交目标:你的PrimeFaces按钮可能直接调用了
#{loginBean.authenticate()},但Spring Security的UsernamePasswordAuthenticationFilter期望在特定URL(默认是/login)处理登录请求。更新表单提交到这个URL,并关闭AJAX(Spring Security默认过滤器不支持AJAX请求):<h:form> <p:inputText id="username" value="#{loginBean.username}" /> <p:password id="password" value="#{loginBean.password}" /> <p:commandButton value="Login" action="#{request.contextPath}/login" ajax="false" /> </h:form> - Spring Security配置错误:确保你的安全配置类(继承
WebSecurityConfigurerAdapter)正确映射了登录页面和处理URL:@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login.xhtml") // 你的JSF登录页面 .loginProcessingUrl("/login") // 和表单的action URL匹配 .defaultSuccessUrl("/dashboard.xhtml") // 登录成功后跳转页面 .failureUrl("/login.xhtml?error=true"); // 登录失败后跳转页面 } - 缺少PasswordEncoder:Spring Security 5强制要求密码编码器,如果你还没配置,添加这个到安全配置中:
同时确保你的@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }UserDetailsService在存储/获取密码时使用这个编码器。
修复这些后,当表单提交时,Spring Security会自动调用你的loadUserByUsername()方法,处理密码验证并完成跳转。你的LoginBean只需要保存表单的用户名/密码值即可——不需要自定义认证方法(除非你要做登录后的额外逻辑,可以在认证成功后触发)。
问题2:loadUserByUsername()返回的UserDetails去哪了?
这个问题问得很好!当loadUserByUsername()返回有效的UserDetails对象后,Spring Security会用它做这些关键操作:
- 密码验证:它会将
UserDetails中的密码和提交的密码(通过你配置的PasswordEncoder)进行比对。 - 创建认证Token:如果验证通过,Spring Security会创建一个
UsernamePasswordAuthenticationToken,包含UserDetails的所有数据(用户名、权限等)。 - 存储到SecurityContext:这个Token会被存入
SecurityContextHolder,并绑定到当前用户的HttpSession中。这意味着你可以在应用的任何地方访问已认证用户的数据:- 在Spring管理的Bean中(包括登录后的LoginBean):
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; // 在你的Bean方法中 UserDetails currentUser = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); String username = currentUser.getUsername(); Collection<? extends GrantedAuthority> roles = currentUser.getAuthorities(); - 或者用
@AuthenticationPrincipal注解更简洁地注入:public void postLoginAction(@AuthenticationPrincipal UserDetails userDetails) { // 在这里使用userDetails } - 在JSF页面中,你可以通过EL表达式访问基础用户信息:
Welcome, #{request.userPrincipal.name}!
- 在Spring管理的Bean中(包括登录后的LoginBean):
UserDetails对象本质上是整个会话中已认证用户身份和权限的唯一可信来源。
内容的提问来源于stack exchange,提问作者Newbie
相关产品推荐
相关产品推荐

