JavaEE學習之Spring Security3.x——模擬數據庫實現用戶,權限,資源的管理


一、引言

因項目需要最近研究了下Spring Security3.x,並模擬數據庫實現用戶,權限,資源的管理。

二、准備

1.了解一些Spring MVC相關知識;

2.了解一些AOP相關知識;

3.了解Spring;

4.了解Maven,並安裝。

三、實現步驟

本示例中使用的版本是Spring Security3.2.2.通過數據庫實現Spring Security認證授權大致需要以下幾個步驟:

1.新建maven web project(因為本示例使用的是maven來構建的),項目結構如下,忽略紅叉叉:

2.在pom文件中添加SpringMVC,Spring Security3.2等依賴的相關jar包,代碼如下:

 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 2   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 3   <modelVersion>4.0.0</modelVersion>
 4   <groupId>com.wzhang</groupId>
 5   <artifactId>spring-mvc-security-helloworld</artifactId>
 6   <packaging>war</packaging>
 7   <version>1.0</version>
 8   <name>spring-mvc-security-helloworld Maven Webapp</name>
 9   <url>http://maven.apache.org</url>
10 <dependencies>
11         <dependency>
12             <groupId>junit</groupId>
13             <artifactId>junit</artifactId>
14             <version>3.8.1</version>
15         </dependency>
16         <dependency>
17             <groupId>commons-logging</groupId>
18             <artifactId>commons-logging</artifactId>
19             <version>1.1.1</version>
20             <scope>compile</scope>
21             <optional>true</optional>
22         </dependency>
23         <dependency>
24             <groupId>org.springframework</groupId>
25             <artifactId>spring-web</artifactId>
26             <version>3.2.3.RELEASE</version>
27         </dependency>
28         <dependency>
29             <groupId>org.springframework</groupId>
30             <artifactId>spring-security-core</artifactId>
31             <version>3.2.2.RELEASE</version>
32         </dependency>
33         <dependency>
34             <groupId>org.springframework</groupId>
35             <artifactId>spring-beans</artifactId>
36             <version>3.2.3.RELEASE</version>
37         </dependency>
38         <dependency>
39             <groupId>org.springframework</groupId>
40             <artifactId>spring-context</artifactId>
41             <version>3.2.3.RELEASE</version>
42         </dependency>
43         <dependency>
44             <groupId>org.springframework.security</groupId>
45             <artifactId>spring-security-config</artifactId>
46             <version>3.2.2.RELEASE</version>
47             <scope>compile</scope>
48         </dependency>
49         <dependency>
50             <groupId>org.springframework</groupId>
51             <artifactId>spring-webmvc</artifactId>
52             <version>3.2.3.RELEASE</version>
53         </dependency>
54         <dependency>
55             <groupId>org.springframework.security</groupId>
56             <artifactId>spring-security-web</artifactId>
57             <version>3.2.2.RELEASE</version>
58             <scope>compile</scope>
59         </dependency>
60         <dependency>
61             <groupId>org.springframework</groupId>
62             <artifactId>spring-core</artifactId>
63             <version>3.2.3.RELEASE</version>
64             <scope>compile</scope>
65             <exclusions>
66                 <exclusion>
67                     <artifactId>commons-logging</artifactId>
68                     <groupId>commons-logging</groupId>
69                 </exclusion>
70             </exclusions>
71         </dependency>
72         <dependency>
73             <groupId>jstl</groupId>
74             <artifactId>jstl</artifactId>
75             <version>1.2</version>
76         </dependency>
77         <dependency>
78             <groupId>log4j</groupId>
79             <artifactId>log4j</artifactId>
80             <version>1.2.17</version>
81         </dependency>
82         <dependency>
83             <groupId>javax.servlet</groupId>
84             <artifactId>servlet-api</artifactId>
85             <version>2.5</version>
86         </dependency>
87 </dependencies>
88   <build>
89     <finalName>spring-mvc-security-helloworld</finalName>
90     
91   </build>
92 </project>
View Code

3.實現FilterInvocationSecurityMetadataSource接口,完成從數據庫中獲取資源權限的關系;

  a.為了模擬數據庫我這里定義了幾個類/接口:ResourceDao.java(訪問數據庫資源的接口),ResourceDaoImpl.java(訪問數據庫資源的實現類).代碼如下:  

package com.wzhang.dao;

import java.util.Map;

public interface ResourceDao {
    /**
     * 獲取資源權限列表
     * @return
     */
    Map<String,String> getResources();
}

/********************以下是ResourceDao實現類 ************************/

package com.wzhang.dao.impl;

import java.util.HashMap;
import java.util.Map;

import com.wzhang.common.RoleConstants;
import com.wzhang.dao.ResourceDao;

public class ResourceDaoImpl implements ResourceDao {

    /**
     * 獲取所有資源權限映射
     * key-URL
     * value-Role
     */
    public Map<String, String> getResources() {
        Map<String, String> map = new HashMap<String, String>();
        map.put("/admin**", RoleConstants.ROLE_ADMIN);
        map.put("/index**", RoleConstants.ROLE_USER);
        return map;
    }

}
View Code

  b.自定義FilterInvocationSecurityMetadataSource接口實現類,利用剛剛的接口和實現類,實現從數據庫獲取資源權限的關系,代碼如下:

  1 package com.wzhang.security.service;
  2 
  3 import java.util.ArrayList;
  4 import java.util.Collection;
  5 import java.util.HashMap;
  6 import java.util.Iterator;
  7 import java.util.Map;
  8 import java.util.Map.Entry;
  9 
 10 import org.apache.log4j.Logger;
 11 import org.springframework.security.access.ConfigAttribute;
 12 import org.springframework.security.access.SecurityConfig;
 13 import org.springframework.security.web.FilterInvocation;
 14 import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
 15 import org.springframework.util.AntPathMatcher;
 16 import org.springframework.util.PathMatcher;
 17 
 18 import com.wzhang.dao.ResourceDao;
 19 import com.wzhang.dao.impl.ResourceDaoImpl;
 20 
 21 /**
 22  * 資源源數據定義,即定義某一資源可以被哪些角色訪問
 23  * @author wzhang
 24  *
 25  */
 26 public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource  {
 27 
 28     private static final Logger logger = Logger
 29             .getLogger(CustomFilterInvocationSecurityMetadataSource .class);
 30 
 31     private static Map<String, Collection<ConfigAttribute>> resourceMap = null;
 32     private PathMatcher pathMatcher = new AntPathMatcher();
 33     
 34     private ResourceDao resourceDao;    
 35     
 36     public CustomFilterInvocationSecurityMetadataSource(ResourceDao resourceDao ){
 37         this.resourceDao =resourceDao;
 38         resourceMap = loadResourceMatchAuthority();
 39     }
 40 
 41     public Collection<ConfigAttribute> getAllConfigAttributes() {
 42 
 43         return null;
 44     }
 45 
 46     public CustomFilterInvocationSecurityMetadataSource  () {
 47         super();
 48         this.resourceDao  = new ResourceDaoImpl();
 49         resourceMap = loadResourceMatchAuthority();
 50     }
 51 
 52     /**
 53      * 加載資源與權限的映射關系
 54      * 
 55      * @return
 56      */
 57     private Map<String, Collection<ConfigAttribute>> loadResourceMatchAuthority() {
 58 
 59         Map<String, Collection<ConfigAttribute>> map = new HashMap<String, Collection<ConfigAttribute>>();
 60 
 61         // 獲取資源權限映射key:url,value:role
 62         Map<String, String> configs = resourceDao.getResources();
 63         for (Entry<String, String> entry : configs.entrySet()) {
 64             Collection<ConfigAttribute> list = new ArrayList<ConfigAttribute>();
 65 
 66             String[] vals = entry.getValue().split(",");
 67             for (String val : vals) {
 68                 ConfigAttribute config = new SecurityConfig(val);
 69                 list.add(config);
 70             }
 71             map.put(entry.getKey(), list);
 72         }
 73 
 74         return map;
 75 
 76     }
 77 
 78     public Collection<ConfigAttribute> getAttributes(Object object)
 79             throws IllegalArgumentException {
 80         String url = ((FilterInvocation) object).getRequestUrl();
 81 
 82         System.out.println("requestUrl is " + url);
 83         logger.info("requestUrl is " + url);
 84         
 85         if (resourceMap == null) {
 86             loadResourceMatchAuthority();
 87         }
 88         //比較url是否存在
 89         Iterator<String> ite = resourceMap.keySet().iterator();
 90         while (ite.hasNext()) {
 91             String resURL = ite.next();
 92             if (pathMatcher.match(resURL,url)) {
 93                 return resourceMap.get(resURL);
 94             }
 95         }
 96         return resourceMap.get(url);
 97     }
 98 
 99     public boolean supports(Class<?> clazz) {
100         return true;
101     }
102 }
View Code

4.實現AccessDecisionManager接口,裁定當前用戶對應權限authentication是否包含所請求資源所擁有的權限;

  當用戶訪問某一資源時,會被AccessDecisionManager攔截,並調用decide(...)方法,用以判斷當前用戶是否有權限訪問該資源,如果沒有則拋出異常。代碼如下:

 1 package com.wzhang.security.service;
 2 
 3 import java.util.Collection;
 4 import java.util.Iterator;
 5 
 6 import org.springframework.security.access.AccessDecisionManager;
 7 import org.springframework.security.access.AccessDeniedException;
 8 import org.springframework.security.access.ConfigAttribute;
 9 import org.springframework.security.authentication.InsufficientAuthenticationException;
10 import org.springframework.security.core.Authentication;
11 import org.springframework.security.core.GrantedAuthority;
12 
13 /**
14  * 自定義訪問決策器,決定某個用戶具有的角色,是否有足夠的權限去訪問某個資源 
15  * @author wzhang
16  *
17  */
18 public class CustomAccessDecisionManager implements AccessDecisionManager {
19 
20     /**
21      * 裁定當前用戶對應權限authentication是否包含所請求資源所擁有的權限 如果成立 則通過裁定 否則發生異常
22      */
23     public void decide(Authentication authentication, Object object,
24             Collection<ConfigAttribute> configAttributes)
25             throws AccessDeniedException, InsufficientAuthenticationException {
26         
27         if (configAttributes == null) {
28             return;
29         }
30 
31         // 所請求的資源擁有的權限(一個資源對多個權限)
32         Iterator<ConfigAttribute> iterator = configAttributes.iterator();
33         
34         while (iterator.hasNext()) {
35             ConfigAttribute configAttribute = iterator.next();
36             
37             // 訪問所請求資源所需要的權限
38             String needPermission = configAttribute.getAttribute();
39             
40             System.out.println("needPermission is " + needPermission);
41             
42             // 用戶所擁有的權限authentication
43             for (GrantedAuthority ga : authentication.getAuthorities()) {
44                 if (needPermission.equals(ga.getAuthority())) {
45                     return;
46                 }
47             }
48         }
49 
50         // 沒有權限
51         throw new AccessDeniedException(" No Access Dendied ");
52 
53     }
54 
55     public boolean supports(ConfigAttribute configAttribute) {
56         return true;
57     }
58 
59     public boolean supports(Class<?> clazz) {
60         return true;
61     }
62 
63 }
View Code

5.實現UserDetailsService接口,完成從數據庫獲取用戶-權限的關系。

  a.為了獲取用戶,以及用戶的權限,我這里先定義了兩個bean:UserBean和RoleBean,代碼如下:

  1 /************RoleBean定義***********/
  2 package com.wzhang.domain;
  3 
  4 public class RoleBean {
  5     private int roleId;
  6     private String roleName;
  7     private String roleDesc;
  8     
  9     
 10     public RoleBean() {
 11         super();
 12         // TODO Auto-generated constructor stub
 13     }
 14     public RoleBean(int roleId, String roleName, String roleDesc) {
 15         super();
 16         this.roleId = roleId;
 17         this.roleName = roleName;
 18         this.roleDesc = roleDesc;
 19     }
 20     /**
 21      * @return the roleId
 22      */
 23     public int getRoleId() {
 24         return roleId;
 25     }
 26     /**
 27      * @param roleId the roleId to set
 28      */
 29     public void setRoleId(int roleId) {
 30         this.roleId = roleId;
 31     }
 32     /**
 33      * @return the roleName
 34      */
 35     public String getRoleName() {
 36         return roleName;
 37     }
 38     /**
 39      * @param roleName the roleName to set
 40      */
 41     public void setRoleName(String roleName) {
 42         this.roleName = roleName;
 43     }
 44     /**
 45      * @return the roleDesc
 46      */
 47     public String getRoleDesc() {
 48         return roleDesc;
 49     }
 50     /**
 51      * @param roleDesc the roleDesc to set
 52      */
 53     public void setRoleDesc(String roleDesc) {
 54         this.roleDesc = roleDesc;
 55     }
 56 }
 57 
 58 
 59 /**************UserBean定義*****************/
 60 
 61 
 62 package com.wzhang.domain;
 63 
 64 public class UserBean {
 65     private String userName;
 66     private String password;
 67     private Integer access;
 68     private RoleBean role;
 69     
 70     /**
 71      * @return the userName
 72      */
 73     public String getUserName() {
 74         return userName;
 75     }
 76     /**
 77      * @param userName the userName to set
 78      */
 79     public void setUserName(String userName) {
 80         this.userName = userName;
 81     }
 82     /**
 83      * @return the password
 84      */
 85     public String getPassword() {
 86         return password;
 87     }
 88     /**
 89      * @param password the password to set
 90      */
 91     public void setPassword(String password) {
 92         this.password = password;
 93     }
 94     /**
 95      * @return the access
 96      */
 97     public Integer getAccess() {
 98         return access;
 99     }
100     /**
101      * @param access the access to set
102      */
103     public void setAccess(Integer access) {
104         this.access = access;
105     }
106     /**
107      * @return the role
108      */
109     public RoleBean getRole() {
110         return role;
111     }
112     /**
113      * @param role the role to set
114      */
115     public void setRole(RoleBean role) {
116         this.role = role;
117     }
118 }
View Code

  b.接着定義了數據訪問層接口和實現:UserDao.java,UserDaoImpl.java以獲取用戶-權限。代碼如下:

 1 /*********Interface UserDao*************/
 2 
 3 package com.wzhang.dao;
 4 
 5 import com.wzhang.domain.UserBean;
 6 
 7 public interface UserDao {
 8     UserBean getUser(String userName);
 9 }
10 
11 
12 /**********實現類*******************/
13 
14 package com.wzhang.dao.impl;
15 
16 import java.util.ArrayList;
17 import java.util.List;
18 
19 import org.apache.log4j.Logger;
20 
21 import com.wzhang.common.RoleConstants;
22 import com.wzhang.dao.UserDao;
23 import com.wzhang.domain.RoleBean;
24 import com.wzhang.domain.UserBean;
25 
26 public class UserDaoImpl implements UserDao {
27     protected static Logger logger = Logger.getLogger("dao");  
28     public UserBean getUser(String userName) {
29         List<UserBean> users = internalDatabase();  
30           
31         for (UserBean ub : users) {  
32             if (ub.getUserName().equals(userName)) {  
33                 logger.debug("User found");  
34                 return ub;  
35             }  
36         }  
37         logger.error("User does not exist!");  
38         throw new RuntimeException("User does not exist!");
39     }
40     
41     
42      private List<UserBean> internalDatabase() {  
43           
44             List<UserBean> users = new ArrayList<UserBean>();  
45             UserBean user = null;  
46       
47             //創建用戶admin/admin,角色ROLE_ADMIN
48             user = new UserBean();  
49             user.setUserName("admin");        
50             // "admin"經過MD5加密后  
51             user.setPassword("21232f297a57a5a743894a0e4a801fc3");
52             user.setAccess(1);
53             user.setRole(new RoleBean(1,RoleConstants.ROLE_ADMIN,""));      
54             users.add(user);  
55       
56             //創建用戶user/user,角色ROLE_USER
57             user = new UserBean();  
58             user.setUserName("user");        
59             // "user"經過MD5加密后  
60             user.setPassword("ee11cbb19052e40b07aac0ca060c23ee");
61             user.setAccess(2);  
62             user.setRole(new RoleBean(2,RoleConstants.ROLE_USER,""));      
63             users.add(user);  
64       
65             return users;  
66       
67         }  
68 }
View Code

  c.代碼中用到的一些常量,定在在RoleContants.kava類中了:

 1 package com.wzhang.common;
 2 
 3 /**
 4  * 角色常量
 5  * @author wzhang
 6  *
 7  */
 8 public class RoleConstants {
 9     /**
10      * 管理員角色
11      */
12     public static final String ROLE_ADMIN = "ROLE_ADMIN";
13     
14     /**
15      * 普通用戶角色
16      */
17     public static final String ROLE_USER = "ROLE_USER";
18 
19 }
View Code

  d.實現UserDetailsService接口,完成用戶-權限的獲取(實現loadUserByUsername(...)方法):

 1 package com.wzhang.security.service;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Collection;
 5 import java.util.List;
 6 
 7 import org.apache.log4j.Logger;
 8 import org.springframework.security.core.GrantedAuthority;
 9 import org.springframework.security.core.authority.SimpleGrantedAuthority;
10 import org.springframework.security.core.userdetails.User;
11 import org.springframework.security.core.userdetails.UserDetails;
12 import org.springframework.security.core.userdetails.UserDetailsService;
13 import org.springframework.security.core.userdetails.UsernameNotFoundException;
14 
15 import com.wzhang.common.RoleConstants;
16 import com.wzhang.dao.UserDao;
17 import com.wzhang.dao.impl.UserDaoImpl;
18 import com.wzhang.domain.UserBean;
19 
20 /**
21  * 自定義用戶與權限的關系
22  * @author wzhang
23  *
24  */
25 public class CustomUserDetailsService implements UserDetailsService {
26     protected static Logger logger = Logger.getLogger("service");
27     private UserDao userDAO = new UserDaoImpl();
28     
29     /**
30      * 根據用戶名獲取用戶-權限等用戶信息
31      */
32     public UserDetails loadUserByUsername(String username)
33             throws UsernameNotFoundException {
34         
35         UserDetails user = null;
36         try {
37             UserBean dbUser = userDAO.getUser(username);
38             user = new User(dbUser.getUserName(), dbUser.getPassword().toLowerCase(), true, true, true, true,getAuthorities(dbUser));
39         } catch (Exception e) {
40             logger.error("Error in retrieving user");  
41             throw new UsernameNotFoundException("Error in retrieving user"); 
42         }
43         return user;
44     }
45     
46      /** 
47      * 獲得訪問角色權限 
48      *  
49      * @param access 
50      * @return 
51      */  
52     private Collection<GrantedAuthority> getAuthorities(UserBean dbUser) {  
53   
54         List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2);  
55   
56         // 所有的用戶默認擁有ROLE_USER權限  
57         logger.debug("Grant ROLE_USER to this user");  
58         authList.add(new  SimpleGrantedAuthority(RoleConstants.ROLE_USER));  
59   
60         // 如果參數access為1.則擁有ROLE_ADMIN權限  
61         if (dbUser.getRole().getRoleName().equals(RoleConstants.ROLE_ADMIN)) {  
62             logger.debug("Grant ROLE_ADMIN to this user");  
63             authList.add(new  SimpleGrantedAuthority(RoleConstants.ROLE_ADMIN));  
64         }  
65   
66         return authList;  
67     }      
68 
69 }
View Code

6.自定義Filter實現類CustomFilterSecurityInterceptor;

 1 package com.wzhang.web.filter;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.Filter;
 6 import javax.servlet.FilterChain;
 7 import javax.servlet.FilterConfig;
 8 import javax.servlet.ServletException;
 9 import javax.servlet.ServletRequest;
10 import javax.servlet.ServletResponse;
11 
12 import org.apache.log4j.Logger;
13 import org.springframework.security.access.SecurityMetadataSource;
14 import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
15 import org.springframework.security.access.intercept.InterceptorStatusToken;
16 import org.springframework.security.web.FilterInvocation;
17 import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
18 
19 /**
20  * 配置過濾器 
21  * @author wzhang
22  *
23  */
24 public class CustomFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
25     private static final Logger logger = Logger
26             .getLogger(CustomFilterSecurityInterceptor.class);
27     private FilterInvocationSecurityMetadataSource securityMetadataSource;
28 
29     /**
30      * Method that is actually called by the filter chain. Simply delegates to
31      * the {@link #invoke(FilterInvocation)} method.
32      * 
33      * @param request
34      *            the servlet request
35      * @param response
36      *            the servlet response
37      * @param chain
38      *            the filter chain
39      * 
40      * @throws IOException
41      *             if the filter chain fails
42      * @throws ServletException
43      *             if the filter chain fails
44      */
45     public void doFilter(ServletRequest request, ServletResponse response,
46             FilterChain chain) throws IOException, ServletException {
47         FilterInvocation fi = new FilterInvocation(request, response, chain);
48         invoke(fi);
49 
50     }
51 
52     public void invoke(FilterInvocation fi) throws IOException,
53             ServletException {
54         InterceptorStatusToken token = super.beforeInvocation(fi);
55         try {
56             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
57         } catch (Exception e) {
58             logger.error(e.getStackTrace());
59         } finally {
60             super.afterInvocation(token, null);
61         }
62     }
63 
64     public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
65         return this.securityMetadataSource;
66     }
67 
68     public Class<? extends Object> getSecureObjectClass() {
69         return FilterInvocation.class;
70     }
71 
72     public SecurityMetadataSource obtainSecurityMetadataSource() {
73         return this.securityMetadataSource;
74     }
75 
76     public void setSecurityMetadataSource(
77             FilterInvocationSecurityMetadataSource newSource) {
78         this.securityMetadataSource = newSource;
79     }
80 
81     public void destroy() {
82         // TODO Auto-generated method stub
83 
84     }
85 
86     public void init(FilterConfig arg0) throws ServletException {
87         // TODO Auto-generated method stub
88 
89     }
90 
91 }
View Code

7.配置web.xml;

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 5     <display-name>Hello World-Spring MVC Security</display-name>
 6     <!-- Spring MVC -->
 7     <servlet>
 8         <servlet-name>spring</servlet-name>
 9         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
10         <load-on-startup>1</load-on-startup>
11     </servlet>
12     <servlet-mapping>
13         <servlet-name>spring</servlet-name>
14         <url-pattern>/</url-pattern>
15     </servlet-mapping>
16 
17     <listener>
18         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
19     </listener>
20 
21     <context-param>
22         <param-name>contextConfigLocation</param-name>
23         <param-value>
24             /WEB-INF/spring-security.xml
25         </param-value>
26     </context-param>
27 
28     <!-- Spring Security -->
29     <filter>
30         <filter-name>springSecurityFilterChain</filter-name>
31         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
32     </filter>
33 
34     <filter-mapping>
35         <filter-name>springSecurityFilterChain</filter-name>
36         <url-pattern>/*</url-pattern>
37     </filter-mapping>
38 </web-app>
View Code

需要注意的是:

  a.這里的servlet-name配置的是spring,后面的springmvc配置文件就得命名為spring-servlet.xml;

  b.spring-security.xml路徑需要配置正確;

  c.不要忘記配置spring security的flter。

8.配置spring-security.xml;

 1 <beans:beans xmlns="http://www.springframework.org/schema/security"
 2     xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://www.springframework.org/schema/beans
 4     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 5     http://www.springframework.org/schema/security
 6     http://www.springframework.org/schema/security/spring-security-3.2.xsd">
 7 
 8 
 9     <http auto-config="true" 
10         access-denied-page="/denied">
11         <!-- <intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" />
12         <intercept-url pattern="/index" access="hasRole('ROLE_USER')" /> -->
13         <form-login login-page="/login" default-target-url="/welcome"
14             authentication-failure-url="/login?error" username-parameter="username"
15             password-parameter="password" />
16         <logout invalidate-session="true" logout-success-url="/login?logout" />
17 <custom-filter ref="customFilter" before="FILTER_SECURITY_INTERCEPTOR"/> 
18     </http>
19 
20 
21 
22     <!-- 認證管理器,實現用戶認證的入口,主要實現UserDetailsService接口即可 -->
23     <authentication-manager alias="authenticationManager">
24         <authentication-provider user-service-ref="customUserDetailsService">
25             <password-encoder ref="passwordEncoder" />
26         </authentication-provider>
27     </authentication-manager>
28 
29     <!-- 密碼加密方式 -->
30     <beans:bean id="passwordEncoder"
31         class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
32 
33     <!-- 自定義用戶驗證服務 -->
34     <beans:bean id="customUserDetailsService"
35         class="com.wzhang.security.service.CustomUserDetailsService" />
36 
37     <!-- 資源源數據定義,即定義某一資源可以被哪些角色訪問 -->
38     <beans:bean id="customSecurityMetadataSource"
39         class="com.wzhang.security.service.CustomFilterInvocationSecurityMetadataSource" />
40 
41     <!-- 自定義訪問決策器,決定某個用戶具有的角色,是否有足夠的權限去訪問某個資源 -->
42     <beans:bean id="customAccessDecisionManager"
43         class="com.wzhang.security.service.CustomAccessDecisionManager" />
44                     <!--  <beans:property name="allowIfAllAbstainDecisions"
45             value="false" />
46         <beans:property name="decisionVoters">
47             <beans:list>
48                 <beans:bean class="org.springframework.security.access.vote.RoleVoter" />
49                 <beans:bean
50                     class="org.springframework.security.access.vote.AuthenticatedVoter" />
51             </beans:list>
52         </beans:property>  -->
53     <!-- </beans:bean> -->
54 
55 
56     <beans:bean id="customFilter"
57         class="com.wzhang.web.filter.CustomFilterSecurityInterceptor">
58         <beans:property name="authenticationManager" ref="authenticationManager" />
59         <beans:property name="accessDecisionManager" ref="customAccessDecisionManager" />
60         <beans:property name="securityMetadataSource" ref="customSecurityMetadataSource" />
61     </beans:bean> 
62 
63 </beans:beans>
View Code

注意事項:

  a.<intercept-url /> 中配置的資源,已經修改為從數據庫獲取;

  b.需要將自定義的AccessDecisionManager,FilterInvocationSecurityMetadataSource,以及authenticationManager注入到自定義filter中。

9.實例中使用了SpringMVC框架所以還需要配置spring-servlet.xml

 1 <beans xmlns="http://www.springframework.org/schema/beans"
 2     xmlns:context="http://www.springframework.org/schema/context"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="
 5         http://www.springframework.org/schema/beans     
 6         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 7         http://www.springframework.org/schema/context 
 8         http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 9 
10     <!-- 掃描注解組件並且自動的注入spring beans中. -->
11     <!-- 例如,掃描@Controller 和@Service下的文件.所以確保此base-package設置正確. -->
12     <context:component-scan base-package="com.wzhang.*" />
13 
14     <!-- 定義一個視圖解析器。pages下的jsp文件映射到controller-->  
15     <bean
16         class="org.springframework.web.servlet.view.InternalResourceViewResolver">
17         <property name="prefix">
18             <value>/WEB-INF/pages/</value>
19         </property>
20         <property name="suffix">
21             <value>.jsp</value>
22         </property>
23     </bean>
24     
25     <bean id="resourceDao" class="com.wzhang.dao.impl.ResourceDaoImpl" ></bean>
26 </beans>
View Code

10.新建幾個頁面

  a.login.jsp,登錄頁面,任何人都能訪問;

  b.admin.jsp,需要admin權限才能訪問;

  c.index.jsp,user權限,admin權限均可訪問;

  d.hello.jsp歡迎頁面,登錄后跳轉,無需權限也能訪問;

11.新建一個Controller,針對不同的頁面定義不同的@RequestMapping;  

 1 package com.wzhang.web.controller;
 2 
 3 import org.springframework.stereotype.Controller;
 4 import org.springframework.web.bind.annotation.RequestMapping;
 5 import org.springframework.web.bind.annotation.RequestMethod;
 6 import org.springframework.web.bind.annotation.RequestParam;
 7 import org.springframework.web.servlet.ModelAndView;
 8 import org.apache.log4j.Logger;  
 9 
10 @Controller
11 public class HelloController {
12 
13     protected static Logger logger = Logger.getLogger("controller");
14     
15     @RequestMapping(value = { "/", "/welcome" }, method = RequestMethod.GET)
16     public ModelAndView welcome() {
17  
18         ModelAndView model = new ModelAndView();
19         model.addObject("title", "Welcome - Spring Security Hello World");
20         model.addObject("message", "This is welcome page!");
21         model.setViewName("hello");
22         return model;
23  
24     }
25  
26     @RequestMapping(value = "/admin**", method = RequestMethod.GET)
27     public ModelAndView adminPage() {
28  
29         ModelAndView model = new ModelAndView();
30         model.addObject("title", "Admin - Spring Security Hello World");
31         model.addObject("message", "This is protected page!");
32         model.setViewName("admin");
33  
34         return model;
35  
36     }
37  
38     //Spring Security see this :
39     @RequestMapping(value = "/login**", method = RequestMethod.GET)
40     public ModelAndView loginPage(
41         @RequestParam(value = "error", required = false) String error,
42         @RequestParam(value = "logout", required = false) String logout) {
43  
44         ModelAndView model = new ModelAndView();
45         if (error != null) {
46             model.addObject("error", "Invalid username and password!");
47         }
48  
49         if (logout != null) {
50             model.addObject("msg", "You've been logged out successfully.");
51         }
52         model.setViewName("login");
53  
54         return model;
55  
56     }
57     
58     @RequestMapping(value = "/index**", method = RequestMethod.GET)
59     public ModelAndView indexPage() {
60  
61         ModelAndView model = new ModelAndView();
62         model.addObject("title", "User - Home Page");
63         model.addObject("message", "This is User access page!");
64         model.setViewName("index");
65  
66         return model;
67  
68     }
69     
70       
71     /** 
72      * 指定無訪問額權限頁面 
73      *  
74      * @return 
75      */  
76     @RequestMapping(value = "/denied**", method = RequestMethod.GET)  
77     public String deniedPage() {  
78   
79         logger.debug("Received request to show denied page");  
80   
81         return "denied";  
82   
83     }  
84  
85 }
View Code

 

四、測試

編譯運行,

  a.輸入http://localhost:8080/spring-mvc-security-helloworld/admin  將會跳轉登錄頁面:

  

  b.輸入user,user,登錄后訪問剛剛的網頁:

  

  c.退出登錄,重新使用admin,admin訪問

  

從上述結果可以看出我們的自定義用戶,權限,資源認證授權起到了作用。

五、總結

Spring Security3還有很多內容,比如在登錄成功后的做一些處理,自定義一些provider等等。

 源碼下載:spring-mvc-security-helloworld.zip


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM