Spring Security3.1登陆验证(转)

声明:本文是转载的,用来学习用,还望原著见谅原著地址
一、前言
在上一篇http://blog.csdn.net/k10509806/archive/2011/04/28/6369131.aspx文章中,提到的MyUserDetailServiceImpl获取用户权限,在用户没有登陆的时候,Spring Security会让我们自动跳转到默认的登陆界面,但在实际应用绝大多数是用我们自己的登陆界面的,其中就包括一些我们自己的逻辑,比如验证码。所以本人又研究一下,终于摸清了一些如何配置自己的登陆界面的办法。在这里献丑了。
二、Spring Security的过滤器
通过DEBUG可以看到Spring Security的Filter的顺序
Security filter chain: [
ConcurrentSessionFilter
SecurityContextPersistenceFilter
LogoutFilter
MyUsernamePasswordAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
RememberMeAuthenticationFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
MySecurityFilter
FilterSecurityInterceptor
]
Spring Security的登陆验证用的就是MyUsernamePasswordAuthenticationFilter,所以要实现我们自己的验证,可以写一个类并继承MyUsernamePasswordAuthenticationFilter类,重写attemptAuthentication方法。

三、applicationContext-Security.xml配置

<?xml version="1.0" encoding="UTF-8"?>  
<beans:beans xmlns="http://www.springframework.org/schema/security"  
    xmlns:beans="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">  

    <debug/>        
    <http pattern="/js/**" security="none"/>  
    <http pattern="/resource/**" security="none"></http>  
    <http pattern="/login.jsp" security="none"/>  

    <http use-expressions="true" entry-point-ref="authenticationProcessingFilterEntryPoint">  
        <logout/>  
        <!-- 实现免登陆验证 -->  
        <remember-me />  
        <session-management invalid-session-url="/timeout.jsp">  
            <concurrency-control max-sessions="10" error-if-maximum-exceeded="true" />  
        </session-management>  

        <custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER"  />  
        <custom-filter ref="securityFilter" before="FILTER_SECURITY_INTERCEPTOR"/>  
    </http>  

    <!-- 登录验证器 -->  
    <beans:bean id="loginFilter"  
        class="com.huaxin.security.MyUsernamePasswordAuthenticationFilter">  
        <!-- 处理登录的action -->  
        <beans:property name="filterProcessesUrl" value="/j_spring_security_check"></beans:property>  
                <!-- 验证成功后的处理-->  
        <beans:property name="authenticationSuccessHandler" ref="loginLogAuthenticationSuccessHandler"></beans:property>  
                <!-- 验证失败后的处理-->  
        <beans:property name="authenticationFailureHandler" ref="simpleUrlAuthenticationFailureHandler"></beans:property>  
        <beans:property name="authenticationManager" ref="myAuthenticationManager"></beans:property>  
        <!-- 注入DAO为了查询相应的用户 -->  
        <beans:property name="usersDao" ref="usersDao"></beans:property>  
    </beans:bean>  
    <beans:bean id="loginLogAuthenticationSuccessHandler"  
        class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">  
        <beans:property name="defaultTargetUrl" value="/index.jsp"></beans:property>  
    </beans:bean>  
    <beans:bean id="simpleUrlAuthenticationFailureHandler"  
        class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">  
        <!-- 可以配置相应的跳转方式。属性forwardToDestination为true采用forward false为sendRedirect -->  
        <beans:property name="defaultFailureUrl" value="/login.jsp"></beans:property>  
    </beans:bean>  

    <!-- 认证过滤器 -->  
    <beans:bean id="securityFilter" class="com.huaxin.security.MySecurityFilter">  
        <!-- 用户拥有的权限 -->  
        <beans:property name="authenticationManager" ref="myAuthenticationManager" />  
        <!-- 用户是否拥有所请求资源的权限 -->  
        <beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />  
        <!-- 资源与权限对应关系 -->  
        <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />  
    </beans:bean>  
    <!-- 实现了UserDetailsService的Bean -->  
    <authentication-manager alias="myAuthenticationManager">  
        <authentication-provider user-service-ref="myUserDetailServiceImpl" />  
    </authentication-manager>  

    <beans:bean id="myAccessDecisionManager" class="com.huaxin.security.MyAccessDecisionManager"></beans:bean>  
    <beans:bean id="mySecurityMetadataSource" class="com.huaxin.security.MySecurityMetadataSource">  
        <beans:constructor-arg name="resourcesDao" ref="resourcesDao"></beans:constructor-arg>  
    </beans:bean>  
    <beans:bean id="myUserDetailServiceImpl" class="com.huaxin.security.MyUserDetailServiceImpl">  
        <beans:property name="usersDao" ref="usersDao"></beans:property>  
    </beans:bean>  

    <!-- 未登录的切入点 -->  
    <beans:bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">  
        <beans:property name="loginFormUrl" value="/login.jsp"></beans:property>  
    </beans:bean>  
</beans:beans>  

这里特别要说明一下,我们的标签不能配置auto-config,因为这样配置后,依然会采用Spring Security的Filter Chain会与下面我们配的custom-filter冲突,最好会抛异常。还有配置一个切入点entry-point-ref=”authenticationProcessingFilterEntryPoint”,为了在未登陆的时候,跳转到哪个页面,不配也会抛异常。
position表示替换掉Spring Security原来默认的登陆验证Filter。

四、MyUsernamePasswordAuthenticationFilter

package com.huaxin.security;  

import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import javax.servlet.http.HttpSession;  

import org.apache.commons.lang.xwork.StringUtils;  
import org.springframework.security.authentication.AuthenticationServiceException;  
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;  
import org.springframework.security.core.Authentication;  
import org.springframework.security.core.AuthenticationException;  
import org.springframework.security.web.WebAttributes;  
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;  

import com.huaxin.bean.Users;  
import com.huaxin.dao.UsersDao;  

/* 
 *  
 * UsernamePasswordAuthenticationFilter源码 
    attemptAuthentication 
        this.getAuthenticationManager() 
            ProviderManager.java 
                authenticate(UsernamePasswordAuthenticationToken authRequest) 
                    AbstractUserDetailsAuthenticationProvider.java 
                        authenticate(Authentication authentication) 
                            P155 user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); 
                                DaoAuthenticationProvider.java 
                                    P86 loadUserByUsername 
 */  
public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{  
    public static final String VALIDATE_CODE = "validateCode";  
    public static final String USERNAME = "username";  
    public static final String PASSWORD = "password";  

    private UsersDao usersDao;  
    public UsersDao getUsersDao() {  
        return usersDao;  
    }  
    public void setUsersDao(UsersDao usersDao) {  
        this.usersDao = usersDao;  
    }  

    @Override  
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {  
        if (!request.getMethod().equals("POST")) {  
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());  
        }  
        //检测验证码  
        checkValidateCode(request);  

        String username = obtainUsername(request);  
        String password = obtainPassword(request);  

        //验证用户账号与密码是否对应  
        username = username.trim();  

        Users users = this.usersDao.findByName(username);  

        if(users == null || !users.getPassword().equals(password)) {  
    /* 
              在我们配置的simpleUrlAuthenticationFailureHandler处理登录失败的处理类在这么一段 
        这样我们可以在登录失败后,向用户提供相应的信息。 
        if (forwardToDestination) { 
            request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception); 
        } else { 
            HttpSession session = request.getSession(false); 

            if (session != null || allowSessionCreation) { 
                request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception); 
            } 
        } 
     */  
            throw new AuthenticationServiceException("用户名或者密码错误!");   
        }  

        //UsernamePasswordAuthenticationToken实现 Authentication  
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);  
        // Place the last username attempted into HttpSession for views  

        // 允许子类设置详细属性  
        setDetails(request, authRequest);  

        // 运行UserDetailsService的loadUserByUsername 再次封装Authentication  
        return this.getAuthenticationManager().authenticate(authRequest);  
    }  

    protected void checkValidateCode(HttpServletRequest request) {   
        HttpSession session = request.getSession();  

        String sessionValidateCode = obtainSessionValidateCode(session);   
        //让上一次的验证码失效  
        session.setAttribute(VALIDATE_CODE, null);  
        String validateCodeParameter = obtainValidateCodeParameter(request);    
        if (StringUtils.isEmpty(validateCodeParameter) || !sessionValidateCode.equalsIgnoreCase(validateCodeParameter)) {    
            throw new AuthenticationServiceException("验证码错误!");    
        }    
    }  

    private String obtainValidateCodeParameter(HttpServletRequest request) {  
        Object obj = request.getParameter(VALIDATE_CODE);  
        return null == obj ? "" : obj.toString();  
    }  

    protected String obtainSessionValidateCode(HttpSession session) {  
        Object obj = session.getAttribute(VALIDATE_CODE);  
        return null == obj ? "" : obj.toString();  
    }  

    @Override  
    protected String obtainUsername(HttpServletRequest request) {  
        Object obj = request.getParameter(USERNAME);  
        return null == obj ? "" : obj.toString();  
    }  

    @Override  
    protected String obtainPassword(HttpServletRequest request) {  
        Object obj = request.getParameter(PASSWORD);  
        return null == obj ? "" : obj.toString();  
    }  


}  

有时间,大家看看源码吧。
五、login.jsp

body>  
  <span style="color:red"><%=session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) %></span>  
   <form action="j_spring_security_check" method="post">  
    Account:<Input name="username"/><br/>  
    Password:<input name="password" type="password"/><br/>  
    <input value="submit" type="submit"/>  
   </form>  
 </body>  

六、完了,源码大家可以看下我上一篇文章http://blog.csdn.net/k10509806/archive/2011/04/28/6369131.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值