无法进行身份验证:HttpSession为SPRING_SECURITY_CONTEXT返回了null对象

时间:2014-03-16 08:39:49

标签: java spring spring-mvc spring-security

目标:我想允许用户访问我的webapp上的任何页面,/account页除外(除非他们已登录)。我希望这个登录过程非常安全,因此转而使用Spring Security和BCryptPasswordEncoder来处理这个过程。这个webapp是使用Spring的纯Java方法开发的(没有任何xml配置)。

功能正常:转到/account正确地将用户重定向到/login页面。用户还可以正确转到/页面,而无需重定向。

问题:我正在尝试使用自己的自定义UserDetailsService配置Spring Security,但每当我尝试通过JSP视图上的表单登录时,{{1我在loadUserByUsername(String username)中覆盖的方法似乎没有被调用。此外,似乎当用户使用所谓的有效凭据登录时,他们的身份验证不会存储在Spring Security的当前会话中,而是保留UserDetailsService

WebSecurityConfigurerAdapter:

ROLE_ANONYMOUS

的UserDetailsS​​ervice:

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    @Autowired
    private UserDetailsServiceImpl userDetailsServiceImpl;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
    {
        auth
            .userDetailsService(userDetailsServiceImpl)
                .passwordEncoder(bCryptPasswordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception
    {
        web
            .ignoring()
                .antMatchers("/css/**")
                .antMatchers("/js/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http
            .authorizeRequests()
                .antMatchers("/account").hasAnyRole("ROLE_USER", "ROLE_ADMIN")
                .anyRequest().authenticated()
                .and()
            .authorizeRequests()
                .antMatchers("/**").permitAll();

        http
            .formLogin()
                .usernameParameter("j_username")
                .passwordParameter("j_password")
                .loginPage("/login")
                .defaultSuccessUrl("/")
                .failureUrl("/loginfailed")
                .permitAll()
                .and()
            .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/")
                .permitAll();
    }

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

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder()
    {
        return new BCryptPasswordEncoder();
    }
}

的login.jsp:

@Service("userService")
public class UserDetailsServiceImpl implements UserDetailsService
{
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
    {
        username = username.toLowerCase();
        try
        {
            Account account = testAccount(); // See below for more details
            if(account == null)
            {
                throw new UsernameNotFoundException("Could not find user '" + username + "' in the database.");
            }

            List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
            for(Role r : account.getRoles())
            {
                auths.add(new SimpleGrantedAuthority(r.getRole()));
            }

            WebUser user = null;
            try
            {
                user = new WebUser(account.getUserID(), username, account.getPassword(), true, true, true, true, auths);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }

            return user;
        }
        catch(Exception e)
        {
            e.printStackTrace();
            throw new UsernameNotFoundException(username + " not found", e);
        }
    }

    private Account testAccount()
    {
        Account acc = new Account();
        acc.setUserID(1);
        acc.setUsername("admin");
        acc.setPassword("$2a$10$ETHSfGAR8FpNTyO52O7qKuoo2/8Uqdwcqq70/5PN4.8DXTR6Ktiha");
        acc.setDescription("No description.");
        acc.setInfluence(9001);
        acc.setJoinDate("03-15-2014");
        List<Role> roles = new ArrayList<Role>();
        roles.add(new Role(Role.ADMIN)); // Role.ADMIN = "ROLE_ADMIN"
        roles.add(new Role(Role.USER)); // Role.USER = "ROLE_USER"
        return acc;
    }
}

输入:

用户名输入字段(“j_username”):admin
密码输入字段(“j_password”):密码
注意:我在UserDetailsS​​erviceImpl中使用的哈希密码是使用 <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/" /> <title>Login</title> <link rel="stylesheet" type="text/css" href="css/main.css" /> <script type="text/javascript" src="js/main.js"></script> </head> <body onload="document.loginForm.j_username.focus();"> <div id="page_wrap"> <h2><a href="">Login Page</a></h2> <div id="container"> <div id="login"> <form name="loginForm" action="<c:url value='j_spring_security_check' />" method="POST"> <h5>Log in to your account</h5> <p> <label for="name">Username: </label> <input type="text" name="j_username" /> </p> <p> <label for="name">Password: </label> <input type="password" name="j_password" /> </p> <p> <input type="submit" id="submit" value="Log In" name="submit" /> </p> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> </form> <c:if test="${not empty error}"> <div class="errorblock"> Your login attempt was not successful, please try again.<br> Caused: ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message} </div> </c:if> </div><!--end login--> </div><!--end container--> </div><!--end page_wrap--> </body> </html> 生成的

结果: 保留在bCryptPasswordEncoder.encode("password");页面上,不会像成功登录时那样重定向到/login

输出:

/

1 个答案:

答案 0 :(得分:3)

从日志中看,您正在点击拒绝访问权限&#34; / j_spring_security_check&#34;。这是可以理解的,因为你没有将其标记为不受保护。我想你可能只是对默认的登录处理URL(/ @Configuration iirc登录)做出错误的假设。如果您发布到&#34; / login&#34;相反它有用吗?