You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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会用它做这些关键操作:

  1. 密码验证:它会将UserDetails中的密码和提交的密码(通过你配置的PasswordEncoder)进行比对。
  2. 创建认证Token:如果验证通过,Spring Security会创建一个UsernamePasswordAuthenticationToken,包含UserDetails的所有数据(用户名、权限等)。
  3. 存储到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}!
      

UserDetails对象本质上是整个会话中已认证用户身份和权限的唯一可信来源。


内容的提问来源于stack exchange,提问作者Newbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:13:10