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

你可能感兴趣的:(Spring Security)