Spring Security

使用Spring Security 3 來實現多種用戶類型的登錄方式,在我看來,大致分爲兩大步,第一步是控制多種用戶登錄類型的登錄界面的展示,第二步是控制多種用戶登錄的驗證方式,而第二大步又可分爲三個小步來展開,第一小步是驗證過濾器,第二小步是驗證憑證的製作,第三小步是驗證用戶憑證,在這裏我將就這幾步的分析與實現一步一步展開來進行描述。

 

      這裏我假定有這樣一個系統,分爲前臺用戶和後臺用戶兩種用戶類型,針對這兩種不同的用戶,相應的驗證是不一樣的,前臺用戶登錄需要提供郵箱地址和電話號碼,而後臺用戶需要提供我們在登錄方式中最爲常見的用戶名,密碼和驗證碼,兩種登錄類型的登錄界面和登錄的驗證處理流程都不相同,擁有自己的驗證處理,驗證成功的處理,驗證失敗的處理等。這裏我會用四篇文章來詳細闡述整個驗證的流程實現,每一篇文章後都會附有我的項目壓縮文件,有興趣的朋友可以下載來進行嘗試,我使用的是Maven來管理項目,項目的框架是Spring+Hibernate,使用到的開發工具是IntelliJ,這裏我要給IntelliJ打個廣告,當然是無償的,呵呵,在這之前我曾使用過NetBeans,Eclipse等開發工具,IntelliJ是我使用過的最爲優秀的開發工具,有興趣的同學可以嘗試下。

 

Spring Security 3多用戶登錄實現之二 多登錄界面展示

接前講,首先針對一個多種用戶類型的登錄需求,需要先實現多種用戶類型的登錄界面的展示,Spring Security提供了這樣一個接口來幫助我們實現多種用戶類型的登錄界面的展示,這個接口就是AuthenticationEntryPoint, 實現這樣一個接口,我們就可以隨心所欲的控制登錄界面的展示了,當我們訪問一個受權限的資源,而當前又沒有權限訪問時,Spring Security就會將處理導向這個接口的實現。針對前講我所提到的需求,在這裏我將實現前臺用戶和後臺用戶登錄界面的展示,先來看看我的源碼實現吧,在這裏爲了實現多用戶類型的登錄,很多場景我都需要根據相應的請求參數或地址來判斷我需要導向哪個URL地址,我在這裏特實現了一個共用的接口和類,接口名爲DirectUrlResolver。

 

 

 

Java代碼  收藏代碼
  1. package com.template.security.shared;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4.   
  5. /** 
  6.  * Created by IntelliJ IDEA. 
  7.  * User: Zhong Gang 
  8.  * Date: 12-11-9 
  9.  * Time: 下午7:11 
  10.  */  
  11. public interface DirectUrlResolver {  
  12.   
  13.     boolean support(HttpServletRequest request);  
  14.   
  15.     String directUrl();  
  16. }  

 

 

Java代碼  收藏代碼
  1. package com.template.security.shared;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4.   
  5. /** 
  6.  * Created by IntelliJ IDEA. 
  7.  * User: Zhong Gang 
  8.  * Date: 12-11-9 
  9.  * Time: 下午7:12 
  10.  */  
  11. public abstract class AbstractDirectUrlResolver implements DirectUrlResolver {  
  12.     protected String pattern;  
  13.     protected String directUrl;  
  14.   
  15.     @Override  
  16.     public abstract boolean support(HttpServletRequest request);  
  17.   
  18.     @Override  
  19.     public String directUrl() {  
  20.         return this.directUrl;  
  21.     }  
  22.   
  23.     public void setPattern(String pattern) {  
  24.         this.pattern = pattern;  
  25.     }  
  26.   
  27.     public void setDirectUrl(String directUrl) {  
  28.         this.directUrl = directUrl;  
  29.     }  
  30. }  

 

Java代碼  收藏代碼
  1. package com.template.security.shared;  
  2.   
  3. import com.template.utils.StringUtils;  
  4.   
  5. import javax.servlet.http.HttpServletRequest;  
  6.   
  7. /** 
  8.  * Created by IntelliJ IDEA. 
  9.  * User: Zhong Gang 
  10.  * Date: 12-11-9 
  11.  * Time: 下午7:13 
  12.  */  
  13. public class RequestParameterDirectUrlResolver extends AbstractDirectUrlResolver {  
  14.     private String parameterName;  
  15.   
  16.     @Override  
  17.     public boolean support(HttpServletRequest request) {  
  18.         String parameterValue = request.getParameter(parameterName);  
  19.         if (StringUtils.isEmpty(parameterValue)) {  
  20.             return false;  
  21.         }  
  22.         return parameterValue.equals(this.pattern);  
  23.     }  
  24.   
  25.     public void setParameterName(String parameterName) {  
  26.         this.parameterName = parameterName;  
  27.     }  
  28. }  

 

 

 

Java代碼  收藏代碼
  1. package com.template.security.shared;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4.   
  5. /** 
  6.  * Created by IntelliJ IDEA. 
  7.  * User: Zhong Gang 
  8.  * Date: 12-11-9 
  9.  * Time: 下午7:13 
  10.  */  
  11. public class RequestUriDirectUrlResolver extends AbstractDirectUrlResolver {  
  12.   
  13.     @Override  
  14.     public boolean support(HttpServletRequest request) {  
  15.         String requestURI = request.getRequestURI();  
  16.         return requestURI.contains(this.pattern);  
  17.     }  
  18. }  

 

     RequestParameterDirectUrlResolver和RequestUriDirectUrlResolver都實現了DirectUrlResolver這樣一個接口,前者的實現是根據相應請求中的參數來判斷, 而後者的實現是根據相應的請求地址來判斷。

 

    現在讓我們來看看如何通過實現AuthenticationEntryPoint接口來控制什麼時候展示前臺登錄界面,什麼時候展示後臺登錄界面的吧。

 

 

Java代碼  收藏代碼
  1. package com.template.security.login;  
  2.   
  3. import com.template.security.shared.DirectUrlResolver;  
  4. import org.springframework.security.core.AuthenticationException;  
  5. import org.springframework.security.web.AuthenticationEntryPoint;  
  6.   
  7. import javax.servlet.ServletException;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10. import java.io.IOException;  
  11. import java.util.ArrayList;  
  12. import java.util.List;  
  13.   
  14. /** 
  15.  * Created by IntelliJ IDEA. 
  16.  * User: Zhong Gang 
  17.  * Date: 12-11-9 
  18.  * Time: 下午7:40 
  19.  */  
  20. public class MultipleAuthenticationLoginEntry implements AuthenticationEntryPoint {  
  21.     private String defaultLoginUrl;  
  22.     private List<DirectUrlResolver> directUrlResolvers = new ArrayList<DirectUrlResolver>();  
  23.   
  24.   
  25.     @Override  
  26.     public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {  
  27.         for (DirectUrlResolver directUrlResolver : directUrlResolvers) {  
  28.             if (directUrlResolver.support(request)) {  
  29.                 String loginUrl = directUrlResolver.directUrl();  
  30.                 response.sendRedirect(loginUrl);  
  31.                 return;  
  32.             }  
  33.         }  
  34.   
  35.         response.sendRedirect(defaultLoginUrl);  
  36.     }  
  37.   
  38.     public void setDefaultLoginUrl(String defaultLoginUrl) {  
  39.         this.defaultLoginUrl = defaultLoginUrl;  
  40.     }  
  41.   
  42.     public void setDirectUrlResolvers(List<DirectUrlResolver> directUrlResolvers) {  
  43.         this.directUrlResolvers = directUrlResolvers;  
  44.     }  
  45. }  

 

     再來看看在Spring配置文件中是如何對相應的登錄入口進行配置的吧

 

 

Xml代碼  收藏代碼
  1. <beans:bean id="multipleAuthenticationLoginEntry"  
  2.                 class="com.template.security.login.MultipleAuthenticationLoginEntry">  
  3.         <beans:property name="defaultLoginUrl" value="/backend/login"/>  
  4.         <beans:property name="directUrlResolvers">  
  5.             <beans:list>  
  6.                 <beans:ref bean="backendLoginEntry"/>  
  7.                 <beans:ref bean="forendLoginEntry"/>  
  8.             </beans:list>  
  9.         </beans:property>  
  10.     </beans:bean>  
  11.   
  12.     <beans:bean id="backendLoginEntry" class="com.template.security.shared.RequestUriDirectUrlResolver">  
  13.         <beans:property name="pattern" value="/backend"/>  
  14.         <beans:property name="directUrl" value="/backend/login"/>  
  15.     </beans:bean>  
  16.   
  17.     <beans:bean id="forendLoginEntry" class="com.template.security.shared.RequestUriDirectUrlResolver">  
  18.         <beans:property name="pattern" value="/forend"/>  
  19.         <beans:property name="directUrl" value="/forend/login"/>  
  20.     </beans:bean>  

 

   這裏我是根據請求的地址中是否包括backend或forend來判斷用戶是進行前臺登錄或後臺登錄的, 這可以從配置文件中的backendLoginEntry和forendLoginEntry中的pattern屬性看出,這個pattern的作用就是判斷用戶是進行前臺登錄或後臺登錄的依據,而directUrl則是我們想要導向的登錄界面地址。

Spring Security 3多用戶登錄實現之三 驗證過濾器

當填寫完成登錄表單提交後,首先會被對應的提交表單提起的過濾器進行攔截,這裏過濾器的作用就是攔截登錄表單提交驗證請求,並根據相應的表單信息構造對應的登錄憑證,這裏來看看過濾器是如何構造相應的用戶憑證。

 

 

Java代碼  收藏代碼
  1. package com.template.security.filter;  
  2.   
  3. import org.springframework.security.core.Authentication;  
  4. import org.springframework.security.core.AuthenticationException;  
  5. import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;  
  6.   
  7. import javax.servlet.ServletException;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10. import java.io.IOException;  
  11. import java.util.ArrayList;  
  12. import java.util.List;  
  13.   
  14. /** 
  15.  * Created by IntelliJ IDEA. 
  16.  * User: Zhong Gang 
  17.  * Date: 12-11-9 
  18.  * Time: 下午10:00 
  19.  */  
  20. public class MultipleAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {  
  21.     private List<AuthenticationTokenResolver> tokenResolvers = new ArrayList<AuthenticationTokenResolver>();  
  22.   
  23.     /** 
  24.      * @param defaultFilterProcessesUrl the default value for <tt>filterProcessesUrl</tt>. 
  25.      */  
  26.     protected MultipleAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {  
  27.         super(defaultFilterProcessesUrl);  
  28.     }  
  29.   
  30.     @Override  
  31.     public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {  
  32.         for (AuthenticationTokenResolver tokenResolver : tokenResolvers) {  
  33.             if (tokenResolver.support(request)) {  
  34.                 Authentication authentication = tokenResolver.resolve(request);  
  35.                 return this.getAuthenticationManager().authenticate(authentication);  
  36.             }  
  37.         }  
  38.   
  39.         throw new UnsupportedOperationException("No authentication token resolver found!");  
  40.     }  
  41.   
  42.     public void setTokenResolvers(List<AuthenticationTokenResolver> tokenResolvers) {  
  43.         this.tokenResolvers = tokenResolvers;  
  44.     }  
  45. }  

 

 

Java代碼  收藏代碼
  1. package com.template.security.filter;  
  2.   
  3. import org.springframework.security.core.Authentication;  
  4.   
  5. import javax.servlet.http.HttpServletRequest;  
  6.   
  7. /** 
  8.  * Created by IntelliJ IDEA. 
  9.  * User: Zhong Gang 
  10.  * Date: 12-11-9 
  11.  * Time: 下午10:08 
  12.  */  
  13. public interface AuthenticationTokenResolver {  
  14.   
  15.     boolean support(HttpServletRequest request);  
  16.   
  17.   
  18.     Authentication resolve(HttpServletRequest request);  
  19.   
  20. }  

 

 

Java代碼  收藏代碼
  1. package com.template.security.filter;  
  2.   
  3. import com.template.utils.StringUtils;  
  4. import org.springframework.security.core.Authentication;  
  5.   
  6. import javax.servlet.http.HttpServletRequest;  
  7.   
  8. /** 
  9.  * Created by IntelliJ IDEA. 
  10.  * User: Zhong Gang 
  11.  * Date: 12-11-9 
  12.  * Time: 下午10:27 
  13.  */  
  14. public abstract class AbstractAuthenticationTokenResolver implements AuthenticationTokenResolver {  
  15.     protected String parameterName;  
  16.     protected String parameterValue;  
  17.   
  18.     protected AbstractAuthenticationTokenResolver() {  
  19.     }  
  20.   
  21.     protected AbstractAuthenticationTokenResolver(String parameterName) {  
  22.         this.parameterName = parameterName;  
  23.     }  
  24.   
  25.     @Override  
  26.     public boolean support(HttpServletRequest request) {  
  27.         String parameterValue = request.getParameter(parameterName);  
  28.         if (StringUtils.isEmpty(parameterValue)) {  
  29.             return false;  
  30.         }  
  31.         return parameterValue.equals(this.parameterValue);  
  32.     }  
  33.   
  34.     @Override  
  35.     public abstract Authentication resolve(HttpServletRequest request);  
  36.   
  37.     public void setParameterName(String parameterName) {  
  38.         this.parameterName = parameterName;  
  39.     }  
  40.   
  41.     public void setParameterValue(String parameterValue) {  
  42.         this.parameterValue = parameterValue;  
  43.     }  
  44. }  

 

 

Java代碼  收藏代碼
  1. package com.template.security.filter;  
  2.   
  3. import com.template.security.authentication.token.BackendAuthenticationToken;  
  4. import org.springframework.security.core.Authentication;  
  5. import org.springframework.security.core.GrantedAuthority;  
  6. import org.springframework.security.core.authority.SimpleGrantedAuthority;  
  7.   
  8. import javax.servlet.http.HttpServletRequest;  
  9. import java.util.ArrayList;  
  10. import java.util.List;  
  11.   
  12. /** 
  13.  * Created by IntelliJ IDEA. 
  14.  * User: Zhong Gang 
  15.  * Date: 12-11-9 
  16.  * Time: 下午10:29 
  17.  */  
  18. public class BackendAuthenticationTokenResolver extends AbstractAuthenticationTokenResolver {  
  19.   
  20.     protected BackendAuthenticationTokenResolver() {  
  21.         super();  
  22.     }  
  23.   
  24.     @Override  
  25.     public Authentication resolve(HttpServletRequest request) {  
  26.         String username = request.getParameter("username");  
  27.         String password = request.getParameter("password");  
  28.         String captcha = request.getParameter("captcha");  
  29.         List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();  
  30.         authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));  
  31.         return new BackendAuthenticationToken(username, password, authorities, captcha);  
  32.     }  
  33. }  

 

 

Java代碼  收藏代碼
  1. package com.template.security.filter;  
  2.   
  3. import com.template.security.authentication.token.ForendAuthenticationToken;  
  4. import org.springframework.security.core.Authentication;  
  5. import org.springframework.security.core.GrantedAuthority;  
  6. import org.springframework.security.core.authority.SimpleGrantedAuthority;  
  7.   
  8. import javax.servlet.http.HttpServletRequest;  
  9. import java.util.ArrayList;  
  10. import java.util.List;  
  11.   
  12. /** 
  13.  * Created by IntelliJ IDEA. 
  14.  * User: Zhong Gang 
  15.  * Date: 12-11-9 
  16.  * Time: 下午10:29 
  17.  */  
  18. public class ForendAuthenticationTokenResolver extends AbstractAuthenticationTokenResolver {  
  19.   
  20.     protected ForendAuthenticationTokenResolver() {  
  21.         super();  
  22.     }  
  23.   
  24.     @Override  
  25.     public Authentication resolve(HttpServletRequest request) {  
  26.         String email = request.getParameter("email");  
  27.         String phone = request.getParameter("phone");  
  28.         List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();  
  29.         authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));  
  30.         return new ForendAuthenticationToken(email, phone, authorities);  
  31.     }  
  32.   
  33. }  

 

    這裏實現AbstractAuthenticationProcessingFilter接口的類MultipleAuthenticationProcessingFilter,用來根據相應的登錄表單提交信息構造相應的登錄用戶憑證。爲了實現根據前臺登錄表單信息構造前臺用戶憑證,根據後臺登錄表單信息構造後臺用戶憑證,使用了策略模式來實現,實現AbstractAuthenticationTokenResolver接口的BackendAuthenticationTokenResolver和ForendAuthenticationTokenResolver分別用來構造後臺用戶憑證和前臺用戶憑證,再來看看配置文件是如何進行配置的吧。

 

 

Xml代碼  收藏代碼
  1. <beans:bean id="multipleAuthenticationProcessingFilter"  
  2.                 class="com.template.security.filter.MultipleAuthenticationProcessingFilter">  
  3.         <beans:constructor-arg value="/login/check"/>  
  4.         <beans:property name="tokenResolvers">  
  5.             <beans:list>  
  6.                 <beans:ref bean="backendAuthenticationTokenResolver"/>  
  7.                 <beans:ref bean="forendAuthenticationTokenResolver"/>  
  8.             </beans:list>  
  9.         </beans:property>  
  10.         <beans:property name="authenticationManager" ref="authenticationManager"/>  
  11.         <beans:property name="authenticationSuccessHandler" ref="multipleAuthenticationSuccessHandler"/>  
  12.         <beans:property name="authenticationFailureHandler" ref="multipleAuthenticationFailureHandler"/>  
  13.     </beans:bean>  
  14.   
  15.     <beans:bean id="backendAuthenticationTokenResolver"  
  16.                 class="com.template.security.filter.BackendAuthenticationTokenResolver">  
  17.         <beans:property name="parameterName" value="token"/>  
  18.         <beans:property name="parameterValue" value="backend"/>  
  19.     </beans:bean>  
  20.   
  21.     <beans:bean id="forendAuthenticationTokenResolver"  
  22.                 class="com.template.security.filter.ForendAuthenticationTokenResolver">  
  23.         <beans:property name="parameterName" value="token"/>  
  24.         <beans:property name="parameterValue" value="forend"/>  
  25.     </beans:bean>  

 

    這裏不論是前臺登錄還是後臺登錄,都提交到相同的地址/login/check,不過爲了區分請求到底是前臺登錄認證還是後臺登錄認證,這裏使用了一個名爲token的請求參數來區分,當token的值爲backend的時候表明是後臺登錄認證,當token的值爲forend的時候表明是前臺登錄認證。

 

   <custom-filter ref="multipleAuthenticationProcessingFilter" before="FORM_LOGIN_FILTER"/>

 

   這段配置表明自定義的認證過濾器將在Spring Security默認的UsernamePasswordAuthenticationFilter前執行,研究UsernamePasswordAuthenticationFilter源碼你就會發現平時使用到的登錄認證請求地址j_spring_security_check就是被這個過濾器進行攔截並進行處理的,所以如果只是簡單的登錄認證,你只需要在登錄頁面進行一些修改就完成可以了,因爲後臺的處理已經完全交由Spring Security來幫我們處理了。

Spring Security 3多用戶登錄實現之四 用戶憑證

前講講到AuthenticationFilter會攔截我們的登錄表單提交信息並根據相應的信息構造出對應的用戶憑證,這裏的用戶憑證將會貫穿整個Spring Security安全驗證過程,如果驗證用戶憑證成功,我們可以爲相應的用戶憑證分配相應的權限,並將用戶導向登錄成功的界面。來看看這裏的多種類型用戶登錄憑證的實現吧,這裏主要實現了兩種用戶憑證,一種是前臺用戶登錄憑證,一種是後臺用戶登錄憑證。

 

 

Java代碼  收藏代碼
  1. package com.template.security.authentication.token;  
  2.   
  3. import org.springframework.security.authentication.AbstractAuthenticationToken;  
  4. import org.springframework.security.core.GrantedAuthority;  
  5. import org.springframework.security.core.authority.SimpleGrantedAuthority;  
  6.   
  7. import java.util.ArrayList;  
  8. import java.util.List;  
  9.   
  10. /** 
  11.  * Created by IntelliJ IDEA. 
  12.  * User: Zhong Gang 
  13.  * Date: 12-11-4 
  14.  * Time: 下午11:23 
  15.  */  
  16. public class ForendAuthenticationToken extends AbstractAuthenticationToken {  
  17.     private String email;  
  18.     private String phone;  
  19.   
  20.     public ForendAuthenticationToken(String email, String phone, List<GrantedAuthority> grantedAuthorities) {  
  21.         super(grantedAuthorities);  
  22.         this.email = email;  
  23.         this.phone = phone;  
  24.     }  
  25.   
  26.     public String getEmail() {  
  27.         return email;  
  28.     }  
  29.   
  30.     public String getPhone() {  
  31.         return phone;  
  32.     }  
  33.   
  34.     @Override  
  35.     public Object getCredentials() {  
  36.         return null;  
  37.     }  
  38.   
  39.     @Override  
  40.     public Object getPrincipal() {  
  41.         return null;  
  42.     }  
  43. }  

 

 

Java代碼  收藏代碼
  1. package com.template.security.authentication.token;  
  2.   
  3. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;  
  4. import org.springframework.security.core.GrantedAuthority;  
  5.   
  6. import java.util.Collection;  
  7.   
  8. /** 
  9.  * Created by IntelliJ IDEA. 
  10.  * User: Zhong Gang 
  11.  * Date: 12-11-4 
  12.  * Time: 下午11:24 
  13.  */  
  14. public class BackendAuthenticationToken extends UsernamePasswordAuthenticationToken {  
  15.     private String captcha;  
  16.   
  17.     public BackendAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities, String captcha) {  
  18.         super(principal, credentials, authorities);  
  19.         this.captcha = captcha;  
  20.     }  
  21.   
  22.     public String getCaptcha() {  
  23.         return captcha;  
  24.     }  
  25. }  

 

    爲了標誌我們創建的類爲一個用戶憑證並且能夠被Spring Security識別,我們需要實現Authentication接口,因爲Spring Security爲我們提供了一個抽象的憑證,所以這裏我的前臺憑證就繼承了這樣一個抽象的憑證類,名爲AbstractAuthenticationToken, 根據前臺表單的提交信息有郵件地址和電話號碼,所以實現的ForendAuthenticationToken包含這樣兩個屬性,而Spring Security爲我們提供了常見的用戶名和密碼的登錄憑證實現,我的後臺登錄表單信息只是多了一個驗證碼,所以我直接繼承了UsernamePasswordAuthenticationToken這樣一個類。

Spring Security 3多用戶登錄實現之五 驗證用戶憑證

 

有了用戶憑證後, 如何驗證用戶的憑證是否正確呢, 這就需要藉助AuthenticationManager了, AuthenticationManager可以包含多個AuthenticationProvider, 每個AuthenticationProvider都會針對特定的AuthenticationToken, 也就是用戶憑證來驗證相應的用戶憑證是否正確。

 

   來看看我爲了實現驗證前臺用戶憑證和後臺用戶憑證而實現的AuthenticationProvider吧。

 

 

Java代碼  收藏代碼
  1. package com.template.security.authentication.provider;  
  2.   
  3. import com.template.security.authentication.token.BackendAuthenticationToken;  
  4. import org.springframework.security.authentication.AuthenticationProvider;  
  5. import org.springframework.security.authentication.AuthenticationServiceException;  
  6. import org.springframework.security.core.Authentication;  
  7. import org.springframework.security.core.AuthenticationException;  
  8. import org.springframework.security.core.context.SecurityContextHolder;  
  9.   
  10. /** 
  11.  * Created by IntelliJ IDEA. 
  12.  * User: Zhong Gang 
  13.  * Date: 12-11-4 
  14.  * Time: 下午11:16 
  15.  */  
  16. public class BackendAuthenticationProvider implements AuthenticationProvider {  
  17.   
  18.     @Override  
  19.     public Authentication authenticate(Authentication authentication) throws AuthenticationException {  
  20.         BackendAuthenticationToken authenticationToken = (BackendAuthenticationToken) authentication;  
  21. //        String captcha = authenticationToken.getCaptcha();  
  22. //        if (captcha.startsWith("ZZ")) {  
  23. //            throw new AuthenticationServiceException("The captcha is wrong!");  
  24. //        }  
  25.         String username = (String) authenticationToken.getPrincipal();  
  26.         String password = (String) authenticationToken.getCredentials();  
  27.   
  28.         if (username.equalsIgnoreCase("ZHONGGANG") && password.equalsIgnoreCase("123")) {  
  29.             SecurityContextHolder.getContext().setAuthentication(authenticationToken);  
  30.             return authenticationToken;  
  31.         }  
  32.         throw new AuthenticationServiceException("The username or password is not correct!");  
  33.     }  
  34.   
  35.     @Override  
  36.     public boolean supports(Class<?> authentication) {  
  37.         return BackendAuthenticationToken.class.isAssignableFrom(authentication);  
  38.     }  
  39. }  

 

 

Java代碼  收藏代碼
  1. package com.template.security.authentication.provider;  
  2.   
  3. import com.template.security.authentication.token.ForendAuthenticationToken;  
  4. import org.springframework.security.authentication.AuthenticationProvider;  
  5. import org.springframework.security.authentication.AuthenticationServiceException;  
  6. import org.springframework.security.core.Authentication;  
  7. import org.springframework.security.core.AuthenticationException;  
  8. import org.springframework.security.core.context.SecurityContextHolder;  
  9.   
  10. /** 
  11.  * Created by IntelliJ IDEA. 
  12.  * User: Zhong Gang 
  13.  * Date: 12-11-4 
  14.  * Time: 下午11:16 
  15.  */  
  16. public class ForendAuthenticationProvider implements AuthenticationProvider {  
  17.   
  18.     @Override  
  19.     public Authentication authenticate(Authentication authentication) throws AuthenticationException {  
  20.         ForendAuthenticationToken authenticationToken = (ForendAuthenticationToken) authentication;  
  21.         String email = authenticationToken.getEmail();  
  22.         String phone = authenticationToken.getPhone();  
  23.         if (email.endsWith("@qq.com") && phone.startsWith("139")) {  
  24.             authenticationToken.setAuthenticated(true);  
  25.             SecurityContextHolder.getContext().setAuthentication(authenticationToken);  
  26.             return authenticationToken;  
  27.         }  
  28.   
  29.         throw new AuthenticationServiceException("The email or phone is not correct!");  
  30.     }  
  31.   
  32.     @Override  
  33.     public boolean supports(Class<?> authentication) {  
  34.         return ForendAuthenticationToken.class.isAssignableFrom(authentication);  
  35.     }  
  36. }  

 

    不論是前臺用戶憑證驗證還是後臺用戶憑證驗證,都實現了AuthenticationProvider接口,其中的supports方法表明這個AuthenticationProvider需要對哪個類型的用戶憑證進行驗證。這裏我只是進行了一個簡單的驗證,沒有什麼實際意義,如果你的驗證需要與數據庫打交道,你可以在AuthenticationProvider中注入你的服務。來看看配置文件中的相應配置信息吧。

 

 

Xml代碼  收藏代碼
  1. <authentication-manager alias="authenticationManager">  
  2.     <authentication-provider ref="forendAuthenticationProvider"/>  
  3.     <authentication-provider ref="backendAuthenticationProvider"/>  
  4. </authentication-manager>  
  5.   
  6. <beans:bean id="backendAuthenticationProvider"  
  7.             class="com.template.security.authentication.provider.BackendAuthenticationProvider"/>  
  8. <beans:bean id="forendAuthenticationProvider"  
  9.             class="com.template.security.authentication.provider.ForendAuthenticationProvider"/>  

Spring Security 3多用戶登錄實現之六 用戶驗證後處理

驗證用戶後主要有這樣兩種走向,一種是驗證失敗,一種是驗證成功,驗證失敗後應該如何處理呢,驗證成功又該如何處理呢?

 

   驗證失敗的處理需要實現AuthenticationFailureHandler接口,我的前臺用戶認證失敗的處理是這樣的

 

 

Java代碼  收藏代碼
  1. package com.template.security.authentication.handler;  
  2.   
  3. import com.template.security.shared.DirectUrlResolver;  
  4. import org.springframework.security.core.AuthenticationException;  
  5. import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;  
  6.   
  7. import javax.servlet.ServletException;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10. import java.io.IOException;  
  11. import java.util.ArrayList;  
  12. import java.util.List;  
  13.   
  14. /** 
  15.  * Created by IntelliJ IDEA. 
  16.  * User: Zhong Gang 
  17.  * Date: 12-11-9 
  18.  * Time: 下午11:20 
  19.  */  
  20. public class MultipleAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {  
  21.     private List<DirectUrlResolver> resolvers = new ArrayList<DirectUrlResolver>();  
  22.   
  23.     @Override  
  24.     public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {  
  25.         for (DirectUrlResolver resolver : resolvers) {  
  26.             if (resolver.support(request)) {  
  27.                 String directUrl = resolver.directUrl();  
  28.                 setDefaultFailureUrl(directUrl);  
  29.             }  
  30.         }  
  31.   
  32.         super.onAuthenticationFailure(request, response, exception);  
  33.     }  
  34.   
  35.     public void setResolvers(List<DirectUrlResolver> resolvers) {  
  36.         this.resolvers = resolvers;  
  37.     }  
  38. }  

 

    驗證成功的處理需要實現AuthenticationSuccessHandler接口,我的後臺驗證成功處理是這樣的

 

 

Java代碼  收藏代碼
  1. package com.template.security.authentication.handler;  
  2.   
  3. import com.template.security.shared.DirectUrlResolver;  
  4. import org.springframework.security.core.Authentication;  
  5. import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;  
  6.   
  7. import javax.servlet.ServletException;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10. import java.io.IOException;  
  11. import java.util.ArrayList;  
  12. import java.util.List;  
  13.   
  14. /** 
  15.  * Created by IntelliJ IDEA. 
  16.  * User: Zhong Gang 
  17.  * Date: 12-11-9 
  18.  * Time: 下午11:20 
  19.  */  
  20. public class MultipleAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {  
  21.     private List<DirectUrlResolver> resolvers = new ArrayList<DirectUrlResolver>();  
  22.   
  23.     @Override  
  24.     public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {  
  25.         for (DirectUrlResolver resolver : resolvers) {  
  26.             if (resolver.support(request)) {  
  27.                 String directUrl = resolver.directUrl();  
  28.                 setDefaultTargetUrl(directUrl);  
  29.             }  
  30.         }  
  31.   
  32.         super.onAuthenticationSuccess(request, response, authentication);  
  33.     }  
  34.   
  35.     public void setResolvers(List<DirectUrlResolver> resolvers) {  
  36.         this.resolvers = resolvers;  
  37.     }  
  38. }  

 

    不論是前臺驗證成功還是後臺驗證成功,前臺驗證失敗還是後臺驗證失敗我都有不同的處理,前臺驗證成功導向前臺驗證成功界面,後臺驗證成功導向後臺驗證成功界面, 前臺驗證失敗導向前臺登錄界面, 後臺驗證失敗導向後臺登錄界面,所以這裏我使用了前面我書寫的一個通用接口,也就是DirectUrlResolver。來看看驗證處理成功或失敗的配置信息。

 

 

Xml代碼  收藏代碼
  1. <beans:bean id="multipleAuthenticationSuccessHandler"  
  2.              class="com.template.security.authentication.handler.MultipleAuthenticationSuccessHandler">  
  3.      <beans:property name="alwaysUseDefaultTargetUrl" value="true"/>  
  4.      <beans:property name="resolvers">  
  5.          <beans:list>  
  6.              <beans:ref bean="backendAuthenticationSuccessUrlResolver"/>  
  7.              <beans:ref bean="forendAuthenticationSuccessUrlResolver"/>  
  8.          </beans:list>  
  9.      </beans:property>  
  10.  </beans:bean>  
  11.   
  12.  <beans:bean id="backendAuthenticationSuccessUrlResolver"  
  13.              class="com.template.security.shared.RequestParameterDirectUrlResolver">  
  14.      <beans:property name="parameterName" value="token"/>  
  15.      <beans:property name="pattern" value="backend"/>  
  16.      <beans:property name="directUrl" value="/backend/login/success"/>  
  17.  </beans:bean>  
  18.   
  19.  <beans:bean id="forendAuthenticationSuccessUrlResolver"  
  20.              class="com.template.security.shared.RequestParameterDirectUrlResolver">  
  21.      <beans:property name="parameterName" value="token"/>  
  22.      <beans:property name="pattern" value="forend"/>  
  23.      <beans:property name="directUrl" value="/forend/login/success"/>  
  24.  </beans:bean>  
  25.   
  26.  <beans:bean id="multipleAuthenticationFailureHandler"  
  27.              class="com.template.security.authentication.handler.MultipleAuthenticationFailureHandler">  
  28.      <beans:property name="resolvers">  
  29.          <beans:list>  
  30.              <beans:ref bean="backendAuthenticationFailureUrlResolver"/>  
  31.              <beans:ref bean="forendAuthenticationFailureUrlResolver"/>  
  32.          </beans:list>  
  33.      </beans:property>  
  34.  </beans:bean>  
  35.   
  36.  <beans:bean id="backendAuthenticationFailureUrlResolver"  
  37.              class="com.template.security.shared.RequestParameterDirectUrlResolver">  
  38.      <beans:property name="parameterName" value="token"/>  
  39.      <beans:property name="pattern" value="backend"/>  
  40.      <beans:property name="directUrl" value="/backend/login?error=1"/>  
  41.  </beans:bean>  
  42.   
  43.  <beans:bean id="forendAuthenticationFailureUrlResolver"  
  44.              class="com.template.security.shared.RequestParameterDirectUrlResolver">  
  45.      <beans:property name="parameterName" value="token"/>  
  46.      <beans:property name="pattern" value="forend"/>  
  47.      <beans:property name="directUrl" value="/forend/login?error=1"/>  
  48.  </beans:bean>  

 

    這裏還需要將相應的驗證Handler注入到前講的認證處理Filter中。

 

 

發佈了49 篇原創文章 · 獲贊 0 · 訪問量 2988
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章