首页 > 代码库 > JavaEE学习之Spring Security3.x——模拟数据库实现用户,权限,资源的管理
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>
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; }}
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 }
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 wzhang16 *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 // 用户所拥有的权限authentication43 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 }
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 set102 */103 public void setAccess(Integer access) {104 this.access = access;105 }106 /**107 * @return the role108 */109 public RoleBean getRole() {110 return role;111 }112 /**113 * @param role the role to set114 */115 public void setRole(RoleBean role) {116 this.role = role;117 }118 }
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_ADMIN48 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_USER57 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 }
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 }
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 wzhang23 *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 }
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 wzhang22 *23 */24 public class CustomFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {25 private static final Logger logger = Logger26 .getLogger(CustomFilterSecurityInterceptor.class);27 private FilterInvocationSecurityMetadataSource securityMetadataSource;28 29 /**30 * Method that is actually called by the filter chain. Simply delegates to31 * the {@link #invoke(FilterInvocation)} method.32 * 33 * @param request34 * the servlet request35 * @param response36 * the servlet response37 * @param chain38 * the filter chain39 * 40 * @throws IOException41 * if the filter chain fails42 * @throws ServletException43 * if the filter chain fails44 */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 stub83 84 }85 86 public void init(FilterConfig arg0) throws ServletException {87 // TODO Auto-generated method stub88 89 }90 91 }
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.xml25 </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>
需要注意的是:
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="http://www.mamicode.com/false" />46 <beans:property name="decisionVoters">47 <beans:list>48 <beans:bean class="org.springframework.security.access.vote.RoleVoter" />49 <beans:bean50 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>
注意事项:
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 <bean16 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>
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 @Controller11 public class HelloController {12 13 protected static Logger logger = Logger.getLogger("controller");14 15 @RequestMapping(value = http://www.mamicode.com/{"/", "/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 = "http://www.mamicode.com/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 = "http://www.mamicode.com/login**", method = RequestMethod.GET)40 public ModelAndView loginPage(41 @RequestParam(value = "http://www.mamicode.com/error", required = false) String error,42 @RequestParam(value = "http://www.mamicode.com/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 = "http://www.mamicode.com/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 = "http://www.mamicode.com/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 }
四、测试
编译运行,
a.输入http://localhost:8080/spring-mvc-security-helloworld/admin 将会跳转登录页面:
b.输入user,user,登录后访问刚刚的网页:
c.退出登录,重新使用admin,admin访问
从上述结果可以看出我们的自定义用户,权限,资源认证授权起到了作用。
五、总结
Spring Security3还有很多内容,比如在登录成功后的做一些处理,自定义一些provider等等。
源码下载:spring-mvc-security-helloworld.zip