Spring Security3详细配置

时间:2024-10-11 16:03:26

Spring Security3详细配置

表名:RESOURCE 解释:资源表
备注: 资源表

RESOURCE(资源表)

是否主键

字段名

字段描述

数据类型

长度

可空

约束

缺省值

备注

ID

id

INT(11)

11

TYPE

类型(URL,METHOD)

VARCHAR(50)

50

VALUE

URL

VARCHAR(50)

50

MODEL_NAME

模块名

VARCHAR(50)

50

PARENT_ID

父模块ID

VARCHAR(50)

50

表名:ROLE 解释:角色表
备注: 角色表

ROLE(角色表)

是否主键

字段名

字段描述

数据类型

长度

可空

约束

缺省值

备注

ID

id

INT(11)

11

NAME

角色名

VARCHAR(50)

50

DESCRIPTION

角色描述

VARCHAR(50)

50

表名:ROLE_RESOURCE 解释:角色资源表
备注: 角色资源表

ROLE_RESOURCE(角色资源表)

是否主键

字段名

字段描述

数据类型

长度

可空

约束

缺省值

备注

ROLE_ID

角色ID

VARCHAR(50)

50

RESOURCE_ID

资源ID

VARCHAR(50)

50

表名:USER 解释:用户表
备注: 用户表

USER(用户表)

是否主键

字段名

字段描述

数据类型

长度

可空

约束

缺省值

备注

NAME

用户名

VARCHAR(50)

50

PASSWORD

密码

VARCHAR(50)

50

DISABLED

是否有效

CHAR(1)

1

EMAIL

邮箱

VARCHAR(100)

100

表名:USER_ROLE 解释:用户角色表
备注: 用户角色表

USER_ROLE(用户角色表)

是否主键

字段名

字段描述

数据类型

长度

可空

约束

缺省值

备注

USER_ID

用户ID

VARCHAR(50)

50

ROLE_ID

角色ID

VARCHAR(50)

50

相关的jar包可到spring官网下载,我使用的是spring security 3.1.3

首先web.xml配置

  1. <context-param>
  2. <param-name>contextConfigLocation</param-name>
  3. <param-value>
  4. classpath:/config/*.xml
  5. </param-value>
  6. </context-param>
  7. <!-- spring监听 -->
  8. <listener>
  9. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  10. </listener>
  11. <!-- Spring Security会话控制 -->
  12. <listener>
  13. <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
  14. </listener>
  15. <!-- Spring security Filter -->
  16. <filter>
  17. <filter-name>springSecurityFilterChain</filter-name>
  18. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  19. </filter>
  20. <filter-mapping>
  21. <filter-name>springSecurityFilterChain</filter-name>
  22. <url-pattern>/*</url-pattern>
  23. </filter-mapping>

这里主要做了三件事,

1、加载Spring;

2、加载Spring Security;

3、添加Spring Security Session监听器(用于控制登录)

Spring Secirty如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans:beans xmlns="http://www.springframework.org/schema/security"
  3. xmlns:beans="http://www.springframework.org/schema/beans"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  6. http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
  7. <debug/>
  8. <global-method-security  pre-post-annotations="enabled" />
  9. <!-- 此目录下不需要过滤 -->
  10. <http pattern="/js/**" security="none"/>
  11. <http pattern="/resources/**" security="none"/>
  12. <http pattern="/css/**" security="none"/>
  13. <http pattern="/dwr/**" security="none"/>
  14. <http pattern="/images/**" security="none"/>
  15. <http pattern="/login.jsp" security="none"/>
  16. <http use-expressions="true">
  17. <!-- 非匿名用户就允许访问 -->
  18. <intercept-url pattern="/index.jsp" access="isAuthenticated()"/>
  19. <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=true"  always-use-default-target="true" default-target-url="/index.jsp" />
  20. <logout logout-success-url="/login.jsp"/>
  21. <!-- 没有权限访问的页面 -->
  22. <access-denied-handler error-page="/403.jsp"/>
  23. <session-management></session-management>
  24. <remember-me/>
  25. <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
  26. </http>
  27. <!-- 指定提示信息 -->
  28. <beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
  29. <beans:property name="basename" value="classpath:spring-security"></beans:property>
  30. </beans:bean>
  31. <authentication-manager alias="myAuthenticationManager">
  32. <authentication-provider ref="authenticationProvider">
  33. </authentication-provider>
  34. </authentication-manager>
  35. <beans:bean id="authenticationProvider"
  36. class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
  37. <beans:property name="userDetailsService" ref="userdetailService" />
  38. <!--显示用户错误信息-->
  39. <beans:property name="hideUserNotFoundExceptions" value="false" />
  40. <beans:property  name="passwordEncoder" ref="md5password"></beans:property >
  41. </beans:bean>
  42. <!-- 密码加密策略 -->
  43. <beans:bean name="md5password" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"></beans:bean>
  44. <beans:bean name="userdetailService" class="com.yindejin.system.MyAuthenticationManager">
  45. <beans:property name="systemService" ref="systemService"></beans:property>
  46. </beans:bean>
  47. <beans:bean name="myFilter" class="com.yindejin.system.MySecurityFilter">
  48. <!-- 用户拥有的权限 -->
  49. <beans:property name="authenticationManager" ref="myAuthenticationManager" />
  50. <!-- 用户是否拥有所请求资源的权限 -->
  51. <beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />
  52. <!-- 资源与权限对应关系 -->
  53. <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />
  54. </beans:bean>
  55. <beans:bean id="myAccessDecisionManager" class="com.yindejin.system.MyAccessDecisionManager"></beans:bean>
  56. <beans:bean id="mySecurityMetadataSource" class="com.yindejin.system.MySecurityMetadataSource">
  57. <beans:constructor-arg name="systemService" ref="systemService"></beans:constructor-arg>
  58. </beans:bean>
  59. </beans:beans>

<custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>

这里的FILTER_SECURITY_INTERCEPTOR是Spring Security过滤器链中默认的Filter,

他的主要功能是

1、校验用户名、密码;

2、初始化时一次性加载所有的资源角色信息

3、检查用户访问权限

我们自定义的Filter必须在它之前,由于我们自己的过滤器和默认过滤器功能是一样的,所以就替换掉了原来的过滤器。

接下来是myFilter几个关键类

MySecurityFilter

  1. package com.yindejin.system;
  2. import java.io.IOException;
  3. import javax.servlet.Filter;
  4. import javax.servlet.FilterChain;
  5. import javax.servlet.FilterConfig;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.ServletRequest;
  8. import javax.servlet.ServletResponse;
  9. import org.springframework.security.access.SecurityMetadataSource;
  10. import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
  11. import org.springframework.security.access.intercept.InterceptorStatusToken;
  12. import org.springframework.security.web.FilterInvocation;
  13. import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
  14. public class MySecurityFilter extends AbstractSecurityInterceptor implements Filter {
  15. //与applicationContext-security.xml里的myFilter的属性securityMetadataSource对应,
  16. //其他的两个组件,已经在AbstractSecurityInterceptor定义
  17. private FilterInvocationSecurityMetadataSource securityMetadataSource;
  18. @Override
  19. public SecurityMetadataSource obtainSecurityMetadataSource() {
  20. return this.securityMetadataSource;
  21. }
  22. public void doFilter(ServletRequest request, ServletResponse response,
  23. FilterChain chain) throws IOException, ServletException {
  24. FilterInvocation fi = new FilterInvocation(request, response, chain);
  25. invoke(fi);
  26. }
  27. private void invoke(FilterInvocation fi) throws IOException, ServletException {
  28. System.out.println("用户发送请求! ");
  29. InterceptorStatusToken token = null;
  30. token = super.beforeInvocation(fi);
  31. try {
  32. fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
  33. } finally {
  34. super.afterInvocation(token, null);
  35. }
  36. }
  37. public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
  38. return securityMetadataSource;
  39. }
  40. public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
  41. this.securityMetadataSource = securityMetadataSource;
  42. }
  43. public void init(FilterConfig arg0) throws ServletException {
  44. // TODO Auto-generated method stub
  45. }
  46. public void destroy() {
  47. // TODO Auto-generated method stub
  48. }
  49. @Override
  50. public Class<? extends Object> getSecureObjectClass() {
  51. //下面的MyAccessDecisionManager的supports方面必须放回true,否则会提醒类型错误
  52. return FilterInvocation.class;
  53. }}

MySecurityMetadataSource

  1. package com.yindejin.system;
  2. import java.util.ArrayList;
  3. import java.util.Collection;
  4. import java.util.HashMap;
  5. import java.util.LinkedHashMap;
  6. import java.util.List;
  7. import java.util.Map;
  8. import java.util.Set;
  9. import javax.servlet.http.HttpServletRequest;
  10. import org.springframework.security.access.ConfigAttribute;
  11. import org.springframework.security.access.SecurityConfig;
  12. import org.springframework.security.web.FilterInvocation;
  13. import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
  14. import org.springframework.security.web.util.AntPathRequestMatcher;
  15. import org.springframework.security.web.util.RequestMatcher;
  16. import com.yindejin.system.service.ISystemService;
  17. import com.yindejin.vo.Resource;
  18. import com.yindejin.vo.Role;
  19. import com.yindejin.vo.User;
  20. //1 加载资源与权限的对应关系
  21. public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
  22. //由spring调用
  23. public MySecurityMetadataSource(ISystemService systemService) {
  24. this.systemService = systemService;
  25. }
  26. private ISystemService systemService;
  27. public ISystemService getSystemService() {
  28. return systemService;
  29. }
  30. public void setSystemService(ISystemService systemService) {
  31. this.systemService = systemService;
  32. }
  33. private static LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> resourceMap = null;
  34. public Collection<ConfigAttribute> getAllConfigAttributes() {
  35. // TODO Auto-generated method stub
  36. return null;
  37. }
  38. public boolean supports(Class<?> clazz) {
  39. // TODO Auto-generated method stub
  40. return true;
  41. }
  42. //加载所有资源与权限的关系
  43. private Map<String, String> getResource() {
  44. Map<String, String> resourceMap = new HashMap<String, String>();
  45. List<User> users = systemService.getAllUser();
  46. for(User user:users){
  47. for(Role role : user.getUserRoles()) {
  48. Set<Resource> resources = role.getRoleResources();
  49. for(Resource resource : resources) {
  50. String url = resource.getValue();
  51. if(!resourceMap.containsKey(url)) {
  52. resourceMap.put(url, role.getName());
  53. }else{
  54. String roleName = resourceMap.get(url);
  55. resourceMap.put(url, roleName+","+role.getName());
  56. }
  57. }
  58. }
  59. }
  60. return resourceMap;
  61. }
  62. private void loadResourceDefine(){
  63. resourceMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
  64. Map<String, String> resource = getResource();
  65. for(Map.Entry<String, String> entry:resource.entrySet()){
  66. Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
  67. configAttributes.add(new SecurityConfig(entry.getValue()));
  68. resourceMap.put(new AntPathRequestMatcher(entry.getKey()), configAttributes);
  69. }
  70. }
  71. //返回所请求资源所需要的权限
  72. public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
  73. HttpServletRequest request = ((FilterInvocation) object).getRequest();
  74. if(null==resourceMap){
  75. System.out.println("请求地址 " + ((FilterInvocation) object).getRequestUrl());
  76. loadResourceDefine();
  77. System.out.println("我需要的认证:"+resourceMap.toString());
  78. }
  79. for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : resourceMap.entrySet()) {
  80. if (entry.getKey().matches(request)) {
  81. return entry.getValue();
  82. }
  83. }
  84. return null;
  85. }
  86. }

MyAccessDecisionManager

  1. package com.yindejin.system;
  2. import java.util.Collection;
  3. import java.util.Iterator;
  4. import org.springframework.security.access.AccessDecisionManager;
  5. import org.springframework.security.access.AccessDeniedException;
  6. import org.springframework.security.access.ConfigAttribute;
  7. import org.springframework.security.authentication.InsufficientAuthenticationException;
  8. import org.springframework.security.core.Authentication;
  9. import org.springframework.security.core.GrantedAuthority;
  10. //3
  11. public class MyAccessDecisionManager implements AccessDecisionManager {
  12. public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
  13. if(configAttributes == null) {
  14. return;
  15. }
  16. //所请求的资源拥有的权限(一个资源对多个权限)
  17. Iterator<ConfigAttribute> iterator = configAttributes.iterator();
  18. while(iterator.hasNext()) {
  19. ConfigAttribute configAttribute = iterator.next();
  20. //访问所请求资源所需要的权限
  21. String needPermission = configAttribute.getAttribute();
  22. System.out.println("needPermission is " + needPermission);
  23. //用户所拥有的权限authentication
  24. for(GrantedAuthority ga : authentication.getAuthorities()) {
  25. if(needPermission.contains((ga.getAuthority()))) {
  26. return;
  27. }
  28. }
  29. }
  30. //没有权限让我们去捕捉
  31. throw new AccessDeniedException(" 没有权限访问!");
  32. }
  33. public boolean supports(ConfigAttribute attribute) {
  34. // TODO Auto-generated method stub
  35. return true;
  36. }
  37. public boolean supports(Class<?> clazz) {
  38. // TODO Auto-generated method stub
  39. return true;
  40. }
  41. }

MyAuthenticationManager

  1. package com.yindejin.system;
  2. import org.springframework.security.core.userdetails.UserDetails;
  3. import org.springframework.security.core.userdetails.UserDetailsService;
  4. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  5. import com.yindejin.system.service.ISystemService;
  6. import com.yindejin.util.StringUtils;
  7. import com.yindejin.vo.User;
  8. public class MyAuthenticationManager implements UserDetailsService {
  9. private ISystemService systemService;
  10. public void setSystemService(ISystemService systemService) {
  11. this.systemService = systemService;
  12. }
  13. @Override
  14. public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
  15. if(!StringUtils.isEmpty(userName)){
  16. throw new UsernameNotFoundException("用户名不能为空!");
  17. }
  18. User user = systemService.loginByUserName(userName);
  19. if (user == null) {
  20. throw new UsernameNotFoundException("用户名或密码错误!");
  21. }
  22. return user;
  23. }
  24. }

User

  1. package com.yindejin.vo;
  2. import java.util.ArrayList;
  3. import java.util.Collection;
  4. import java.util.HashMap;
  5. import java.util.HashSet;
  6. import java.util.List;
  7. import java.util.Map;
  8. import java.util.Set;
  9. import javax.persistence.Transient;
  10. import org.springframework.security.core.GrantedAuthority;
  11. import org.springframework.security.core.authority.GrantedAuthorityImpl;
  12. import org.springframework.security.core.userdetails.UserDetails;
  13. /**
  14. * User entity. @author MyEclipse Persistence Tools
  15. */
  16. public class User implements UserDetails {
  17. // Fields
  18. private Integer id;
  19. private String name;
  20. private String password = "123456";
  21. private Integer disabled = 0;
  22. private String email;
  23. public String getEmail() {
  24. return email;
  25. }
  26. public void setEmail(String email) {
  27. this.email = email;
  28. }
  29. private Set<Role> userRoles = new HashSet<Role>();
  30. @Transient
  31. private Map<String, List<Resource>> roleResources;
  32. // Constructors
  33. public Integer getId() {
  34. return id;
  35. }
  36. public void setId(Integer id) {
  37. this.id = id;
  38. }
  39. public String getName() {
  40. return name;
  41. }
  42. public void setName(String name) {
  43. this.name = name;
  44. }
  45. public String getPassword() {
  46. return password;
  47. }
  48. public void setPassword(String password) {
  49. this.password = password;
  50. }
  51. public Integer getDisabled() {
  52. return disabled;
  53. }
  54. public void setDisabled(Integer disabled) {
  55. this.disabled = disabled;
  56. }
  57. public Set<Role> getUserRoles() {
  58. return userRoles;
  59. }
  60. public void setUserRoles(Set<Role> userRoles) {
  61. this.userRoles = userRoles;
  62. }
  63. /** default constructor */
  64. public User() {
  65. }
  66. public String getUsername() {
  67. return name;
  68. }
  69. public boolean isAccountNonExpired() {
  70. return true;
  71. }
  72. public boolean isAccountNonLocked() {
  73. return true;
  74. }
  75. public boolean isCredentialsNonExpired() {
  76. return true;
  77. }
  78. public boolean isEnabled() {
  79. return this.disabled==0?true:false;
  80. }
  81. /**
  82. * @return the roleResources
  83. */
  84. public Map<String, List<Resource>> getRoleResources() {
  85. // init roleResources for the first time
  86. if(this.roleResources == null) {
  87. this.roleResources = new HashMap<String, List<Resource>>();
  88. for(Role role : this.userRoles) {
  89. String roleName = role.getName();
  90. Set<Resource> resources = role.getRoleResources();
  91. for(Resource resource : resources) {
  92. String key = roleName + "_" + resource.getType();
  93. if(!this.roleResources.containsKey(key)) {
  94. this.roleResources.put(key, new ArrayList<Resource>());
  95. }
  96. this.roleResources.get(key).add(resource);
  97. }
  98. }
  99. }
  100. return this.roleResources;
  101. }
  102. @SuppressWarnings("deprecation")
  103. @Override
  104. public Collection<GrantedAuthority> getAuthorities() {
  105. Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
  106. for(Role role : getUserRoles()){
  107. authSet.add(new GrantedAuthorityImpl(role.getName()));
  108. }
  109. return authSet;
  110. }
  111. }