我这边配置了security,验证成功后,不知道为什么没有把userdetails保存到SecurityContext中。
但是
request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");能获取到userDetails.
这个是为什么?
网络上有说,我是因为配置了 security="none"所以不会放到SecurityContext中,但是实际上我只对登录的放行,其他的都需要过滤。具体我还是贴一下关键代码。
XML配置
<sec:http pattern="/login/login.do" security="none" />
<sec:http pattern="error.jsp" security="none" />
<sec:http pattern="index.jsp" security="none" />
<sec:http pattern="/syscode/type.do" security="none" />
<sec:http pattern="/login/loginpage.do" security="none" />

<sec:http use-expressions="true" auto-config="true" access-denied-page="/views/accessDenied.jsp">
<sec:form-login login-page="/login/loginpage.do"
authentication-failure-url="/index.jsp"
default-target-url="/login/main.do"

/>
<sec:logout invalidate-session="true" logout-success-url="/index.jsp" />
<!--<检测失效的sessionId,超时时定位到另外一个URL 
<sec:session-management invalid-session-url="/views/sessionTimeout.jsp" />-->
<sec:custom-filter ref="worktimesLoginProcessingFilter" before="FORM_LOGIN_FILTER" />
<sec:custom-filter ref="worktimesSessionFilter" before="CONCURRENT_SESSION_FILTER" />

</sec:http>
<bean class="org.springframework.security.authentication.event.LoggerListener" />
<bean id="worktimesLoginProcessingFilter" class="com.worktimes.core.security.WorktimesLoginProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationFailureHandler" ref="simpleUrlAuthenticationFailureHandler" />
<property name="sessionAuthenticationStrategy" ref="sas" />
<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
</bean>XML的配置很简单,
关键是配置了一个worktimesLoginProcessingFilter的过滤器,实现AbstractUserDetailsAuthenticationProvider接口。
在WorktimesAuthenticationProvider中,装配WorktimesUsernamePasswordAuthenticationToken后,保存到AuthenticationManager中,具体代码如下:@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException,
IOException, ServletException { String loginType = request.getParameter("loginType");
String username = request.getParameter("account");
    String password = request.getParameter("password");
if(loginType == null){
throw new CaptchaException("loginType is null!");
}
if("0".equals(loginType)){
loginType = Constants.NormalUser;
}else{
loginType = Constants.SystemUser;
}
WorktimesUsernamePasswordAuthenticationToken authRequest = null;
this.logger.info("Captcha enabled!");
//验证码
String captchaValue = (String)request.getSession().getAttribute("Rand");
String captchaReq = request.getParameter("captcha");
if (!captchaReq.equals(captchaValue)) {
throw new CaptchaException("Bad captcha!");
}
request.getSession().removeAttribute("Rand");

    request.getSession().setAttribute("username", username);
            //装配UsernamePasswordAuthenticationToken
    authRequest = new WorktimesUsernamePasswordAuthenticationToken(username, password, loginType);
    authRequest.setLoginType(loginType);
    authRequest.setUserIP(CommonFunction.getIpAddr(request));
            //保存到AuthenticationManager中
    return getAuthenticationManager().authenticate(authRequest);
}我看文档,到这里就会把WorktimesUsernamePasswordAuthenticationToken放进SecurityContext中。不知道对不对...
在这步执行完后,spring security会进行用户名密码验证,实现AbstractUserDetailsAuthenticationProvider接口@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
WorktimesUsernamePasswordAuthenticationToken worktimesAuthentication = (WorktimesUsernamePasswordAuthenticationToken) authentication;
String presentedPassword = worktimesAuthentication.getCredentials().toString();
if(!presentedPassword.equals(userDetails.getPassword())){
this.logger.debug("Authentication failed: password does not match stored value");
        throw new BadCredentialsException("Bad credentials");
}

} @Override
protected UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
WorktimesUsernamePasswordAuthenticationToken worktimesAuthentication = (WorktimesUsernamePasswordAuthenticationToken) authentication;
userDetailsService.loginType=worktimesAuthentication.getLoginType();
WorktimesUserInfo userInfo = (WorktimesUserInfo)userDetailsService.loadUserByUsername(worktimesAuthentication.getName());
if(userInfo.getStatus().equals("1")){
throw new AccountExpiredException("用户已注销!");
}
return userInfo;
}先执行retrieveUser获取User对象,通过userDetailsService到数据库查询我这边的帐户,这步代码就不贴了,无非是查数据库数据,填充WorktimesUserInfo。对了,WorktimesUserInfo是要继承User。然后账号没问题,springsecurity会执行additionalAuthenticationChecks检查用户密码是否正确。我到这边密码也是正常的。
关键代码就是这些,最后执行成功后,页面跳转根据XML文件中配置的authenticationSuccessHandler跳转到/login/main.do,这个也是正常。接下来获取用户就有问题了,public static WorktimesUserInfo getLoginUser(){
Object userInfo = null;
SecurityContext securityContext = SecurityContextHolder.getContext();
System.out.println("认证成功后获取securityContext:"+securityContext);
System.out.println("认证成功后获取getAuthentication:"+securityContext.getAuthentication());
if(securityContext != null && securityContext.getAuthentication() !=null ){
userInfo = securityContext.getAuthentication().getPrincipal();
if(userInfo instanceof WorktimesUserInfo){
return (WorktimesUserInfo) userInfo;
}

return null;
}定义一个方法获取用户信息,但是securityContext正常,能打印出来值,但是
securityContext.getAuthentication()是null。这个就郁闷了,不知道什么情况,查了很多资料都没办法解决........
还请大神解答.....

解决方案 »

  1.   

    这个问题已经解决了 = =
    现在有个新的问题
    登录页面login.jsp
    如果是用form表单的submit提交,则获取不到文本框的值。var url = appContext+'/j_spring_security_check';
    var formObj = $("#loginForm")[0];
    formObj.action = url;
    $.messager.progress('close');
    formObj.submit();然后public class WorktimesLoginProcessingFilter extends AbstractAuthenticationProcessingFilter {
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
    HttpServletResponse response) throws AuthenticationException,
    IOException, ServletException {
    String loginType = request.getParameter("loginType");
    String username = request.getParameter("account");
        String password = request.getParameter("password");
    System.out.println("loginType:"+loginType);
    System.out.println("username:"+username);
    System.out.println("password:"+password);
                    //余下代码略....
    }
    }打印出来全是null
      

  2.   

    你这个ppContext+'/j_spring_security_check'是spring secuirty的login-processing-url ?
    把你spring secuirty拦截配置那一段发一下
      

  3.   

    你这个ppContext+'/j_spring_security_check'是spring secuirty的login-processing-url ?
    把你spring secuirty拦截配置那一段发一下

    我只贴一下重点部分,中间乱七八糟的就不贴了<context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:config/spring/applicationContext.xml,
            classpath:config/spring/datasource.xml,
            classpath:config/spring/worktimes-security.xml
            </param-value>
        </context-param>
    <filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
    <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>*.do</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/j_spring_security_check</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/j_spring_security_logout</url-pattern>
        </filter-mapping>
      

  4.   

    form的action是配置spring security的login-processing-url ,不是web.xml的filter。
      

  5.   


    我配置在login-processing-url中也是不行的。<sec:form-login login-page="/login/loginpage.do"
    authentication-failure-url="/index.jsp"
    login-processing-url="/j_spring_security_check"
    default-target-url="/login/main.do"/>