永远不会调用bean / controller的Spring Security身份验证

时间:2018-02-25 09:01:08

标签: spring jsf spring-security

我是Spring的新手,目前正在学习Spring Web Security登录并遇到了一些问题。我使用的是Spring Security 5,JSF 2.2和Primefaces 6.1 首先,我从未调用LoginBean处的身份验证方法。它将通过方法loadUserByUsername()直到返回UserDetails对象,但我的bean中的方法永远不会被调用。我的另一个好奇是UserDetails对象将在loadUserByUsername()方法中返回的位置?以下是我的实施:

LoginBean.java

@ManagedBean
@SessionScoped
public class LoginBean extends BaseBean
{
    @Autowired
    private transient AuthenticationManager authenticationManager;

    private String username;
    private String password;

    public String login()
    {
        try
        {
            Authentication request = new UsernamePasswordAuthenticationToken(username, password);
            Authentication result = authenticationManager.authenticate(request);
            SecurityContextHolder.getContext().setAuthentication(result);
            if (result.isAuthenticated())
            {
                Set<String> roles = AuthorityUtils.authorityListToSet(result.getAuthorities());
                if (roles.contains("ROLE_ADMIN"))
                    return SystemUtils.getSavedUrl("admin");
                else if (roles.contains("ROLE_USER"))
                    return SystemUtils.getSavedUrl("user");
            }
        } catch (BadCredentialsException badCredentialsException)
        {
            FacesMessage facesMessage = new FacesMessage(
                    "Login Failed: please check your username/password and try again.");
            FacesContext.getCurrentInstance().addMessage(null, facesMessage);
        } catch (LockedException lockedException)
        {
            FacesMessage facesMessage = new FacesMessage("Account Locked: please contact your administrator.");
            FacesContext.getCurrentInstance().addMessage(null, facesMessage);
        } catch (DisabledException disabledException)
        {
            FacesMessage facesMessage = new FacesMessage("Account Disabled: please contact your administrator.");
            FacesContext.getCurrentInstance().addMessage(null, facesMessage);
        }
        return null;
    }
}

SecurityConfig.java

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    @Autowired
    private UserDetailsService userService;

    @Override
    public void configure(WebSecurity web) throws Exception
    {
        web.debug(true);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http.authorizeRequests().antMatchers("/admin/**").access("hasRole('ADMIN')");
        http.authorizeRequests().antMatchers("/user/**").access("hasRole('USER')");
        // login
        http.formLogin().loginPage("/login.xhtml").permitAll()
                .successHandler(getAuthenticationSuccessHandler())
                .failureHandler(getAuthenticationFailureHandler());
        // logout
        http.logout().logoutSuccessUrl("/index.xhtml").invalidateHttpSession(true);
        // require all requests to be authenticated except for the resources
        http.authorizeRequests().antMatchers("/javax.faces.resource/**", "/**").permitAll().anyRequest()
                .authenticated();
        // not needed as JSF 2.2 is implicitly protected against CSRF
        http.csrf().disable();
        http.exceptionHandling().accessDeniedPage("/403.xhtml");
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.authenticationProvider(getAuthenticationProvider());
    }

    @Bean
    public SimpleUrlAuthenticationFailureHandler getAuthenticationFailureHandler()
    {
        return new CustomeAuthFailureHandler();
    }

    @Bean
    public SimpleUrlAuthenticationSuccessHandler getAuthenticationSuccessHandler()
    {
        return new CustomAuthSuccessHandler();
    }

    @Bean
    public AuthenticationProvider getAuthenticationProvider() throws Exception
    {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userService);
        provider.setPasswordEncoder(new BCryptPasswordEncoder());
        return provider;
    }

    @Bean(name = "authenticationManager")
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception
    {
        return super.authenticationManagerBean();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

AccountServiceImpl.java (实现UserDetailsService的类)

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
    System.out.println("username is:-" + username);
    //My account model is implement UserDetails interface
    AccountModel user = repository.findByUsername(username);
    if (user == null)
    {
        throw new UsernameNotFoundException("No such user: " + username);
    }
    if (user.getRole().isEmpty())
    {
        throw new UsernameNotFoundException("User" + username + "has no authorities");
    }
    System.out.println("Password is:-" + user.getPassword().toString());
    List<GrantedAuthority> authorities = buildUserAuthority(user.getRole());
    user.setAuthorities(new HashSet<>(authorities));

    return user;
}

private List<GrantedAuthority> buildUserAuthority(Set<RoleModel> userRoles)
{
    Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
    // Build user's authorities
    for (RoleModel userRole : userRoles)
    {
        setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
    }
    List<GrantedAuthority> result = new ArrayList<GrantedAuthority>(setAuths);
    return result;
}

login.xhtml

<h:form prependId="false">
    <p:messages showDetail="true" closable="true" autoUpdate="true"
        globalOnly="true" />
    <p:panelGrid>
        <p:row>
            <p:column>
                <p:outputLabel for="username" value="Username: " />
            </p:column>
            <p:column>
                <p:inputText id="username" value="#{loginBean.username}" />
            </p:column>
        </p:row>

        <p:row>
            <p:column>
                <p:outputLabel for="password" value="Password: " />
            </p:column>
            <p:column>
                <p:password id="password" value="#{loginBean.password}" />
            </p:column>
        </p:row>
        <p:row>
            <p:column colspan="2">
                <p:commandButton value="Login" process="@form" ajax="false"
                    actionListener="#{loginBean.login}" />
            </p:column>
        </p:row>
    </p:panelGrid>
</h:form>

通过上面的实现,虽然根据数据库中的数据正确提供了用户名和密码,但登录永远不会成功。我的实施或配置有什么问题吗?另一个问题是虽然在UsernameNotFoundException中抛出了loadUserByUsername,但是异常消息仍未显示在控制台中(但是其他异常消息将显示,只有此异常不会出现),这是正常的吗?

**** 更新 ****

我试图关注this site

  

请确保:

     
      
  • 您没有覆盖login-processing-url的默认映射(默认值为“/ login”,因为选择“/ j_spring_security_check”为
      旧版本的Spring
  •   
  • 将用户和密码输入按钮的ID分别设置为“用户名”和“密码”(请注意较旧的Spring版本具有
      默认设置为“j_xxx”;你可以实际配置这些值   登录的用户名参数和密码参数属性
      元件)
  •   
  • 在按钮定义中使用ajax =“false”
  •   
  • 将prependId =“false”添加到表单定义
  •   
  • 如上所示设置FORWARD和REQUEST调度程序参数
  •   

如第一点所述,我删除loginPage("/login.xhtml"),但当您登录指向您的客户登录页面的网址localhost:8080/Project/login.xhtml时,它只能。如果您通过localhost:8080/Project/login的弹出默认登录页面进行访问,则不起作用 问题是login.xhtml不是默认登录页面,因此在某些情况下,如果用户正在访问需要凭据的页面,它会将用户重定向到默认登录页面/login而不是我的登录页面{ {1}}。

我还尝试将其设置为/login.xhtml,但如果您访问loginPage("/login")之类的网址,则会返回404。

0 个答案:

没有答案