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 |
是 |
||||
|
邮箱 |
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配置
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath:/config/*.xml
- </param-value>
- </context-param>
- <!-- spring监听 -->
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <!-- Spring Security会话控制 -->
- <listener>
- <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
- </listener>
- <!-- Spring security Filter -->
- <filter>
- <filter-name>springSecurityFilterChain</filter-name>
- <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>springSecurityFilterChain</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
这里主要做了三件事,
1、加载Spring;
2、加载Spring Security;
3、添加Spring Security Session监听器(用于控制登录)
Spring Secirty如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans:beans xmlns="http://www.springframework.org/schema/security"
- xmlns:beans="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
- <debug/>
- <global-method-security pre-post-annotations="enabled" />
- <!-- 此目录下不需要过滤 -->
- <http pattern="/js/**" security="none"/>
- <http pattern="/resources/**" security="none"/>
- <http pattern="/css/**" security="none"/>
- <http pattern="/dwr/**" security="none"/>
- <http pattern="/images/**" security="none"/>
- <http pattern="/login.jsp" security="none"/>
- <http use-expressions="true">
- <!-- 非匿名用户就允许访问 -->
- <intercept-url pattern="/index.jsp" access="isAuthenticated()"/>
- <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=true" always-use-default-target="true" default-target-url="/index.jsp" />
- <logout logout-success-url="/login.jsp"/>
- <!-- 没有权限访问的页面 -->
- <access-denied-handler error-page="/403.jsp"/>
- <session-management></session-management>
- <remember-me/>
- <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
- </http>
- <!-- 指定提示信息 -->
- <beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
- <beans:property name="basename" value="classpath:spring-security"></beans:property>
- </beans:bean>
- <authentication-manager alias="myAuthenticationManager">
- <authentication-provider ref="authenticationProvider">
- </authentication-provider>
- </authentication-manager>
- <beans:bean id="authenticationProvider"
- class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
- <beans:property name="userDetailsService" ref="userdetailService" />
- <!--显示用户错误信息-->
- <beans:property name="hideUserNotFoundExceptions" value="false" />
- <beans:property name="passwordEncoder" ref="md5password"></beans:property >
- </beans:bean>
- <!-- 密码加密策略 -->
- <beans:bean name="md5password" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"></beans:bean>
- <beans:bean name="userdetailService" class="com.yindejin.system.MyAuthenticationManager">
- <beans:property name="systemService" ref="systemService"></beans:property>
- </beans:bean>
- <beans:bean name="myFilter" class="com.yindejin.system.MySecurityFilter">
- <!-- 用户拥有的权限 -->
- <beans:property name="authenticationManager" ref="myAuthenticationManager" />
- <!-- 用户是否拥有所请求资源的权限 -->
- <beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />
- <!-- 资源与权限对应关系 -->
- <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />
- </beans:bean>
- <beans:bean id="myAccessDecisionManager" class="com.yindejin.system.MyAccessDecisionManager"></beans:bean>
- <beans:bean id="mySecurityMetadataSource" class="com.yindejin.system.MySecurityMetadataSource">
- <beans:constructor-arg name="systemService" ref="systemService"></beans:constructor-arg>
- </beans:bean>
- </beans:beans>
<custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
这里的FILTER_SECURITY_INTERCEPTOR是Spring Security过滤器链中默认的Filter,
他的主要功能是
1、校验用户名、密码;
2、初始化时一次性加载所有的资源角色信息
3、检查用户访问权限
我们自定义的Filter必须在它之前,由于我们自己的过滤器和默认过滤器功能是一样的,所以就替换掉了原来的过滤器。
接下来是myFilter几个关键类
MySecurityFilter
- package com.yindejin.system;
- import java.io.IOException;
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import org.springframework.security.access.SecurityMetadataSource;
- import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
- import org.springframework.security.access.intercept.InterceptorStatusToken;
- import org.springframework.security.web.FilterInvocation;
- import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
- public class MySecurityFilter extends AbstractSecurityInterceptor implements Filter {
- //与applicationContext-security.xml里的myFilter的属性securityMetadataSource对应,
- //其他的两个组件,已经在AbstractSecurityInterceptor定义
- private FilterInvocationSecurityMetadataSource securityMetadataSource;
- @Override
- public SecurityMetadataSource obtainSecurityMetadataSource() {
- return this.securityMetadataSource;
- }
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain) throws IOException, ServletException {
- FilterInvocation fi = new FilterInvocation(request, response, chain);
- invoke(fi);
- }
- private void invoke(FilterInvocation fi) throws IOException, ServletException {
- System.out.println("用户发送请求! ");
- InterceptorStatusToken token = null;
- token = super.beforeInvocation(fi);
- try {
- fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
- } finally {
- super.afterInvocation(token, null);
- }
- }
- public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
- return securityMetadataSource;
- }
- public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
- this.securityMetadataSource = securityMetadataSource;
- }
- public void init(FilterConfig arg0) throws ServletException {
- // TODO Auto-generated method stub
- }
- public void destroy() {
- // TODO Auto-generated method stub
- }
- @Override
- public Class<? extends Object> getSecureObjectClass() {
- //下面的MyAccessDecisionManager的supports方面必须放回true,否则会提醒类型错误
- return FilterInvocation.class;
- }}
MySecurityMetadataSource
- package com.yindejin.system;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import javax.servlet.http.HttpServletRequest;
- import org.springframework.security.access.ConfigAttribute;
- import org.springframework.security.access.SecurityConfig;
- import org.springframework.security.web.FilterInvocation;
- import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
- import org.springframework.security.web.util.AntPathRequestMatcher;
- import org.springframework.security.web.util.RequestMatcher;
- import com.yindejin.system.service.ISystemService;
- import com.yindejin.vo.Resource;
- import com.yindejin.vo.Role;
- import com.yindejin.vo.User;
- //1 加载资源与权限的对应关系
- public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
- //由spring调用
- public MySecurityMetadataSource(ISystemService systemService) {
- this.systemService = systemService;
- }
- private ISystemService systemService;
- public ISystemService getSystemService() {
- return systemService;
- }
- public void setSystemService(ISystemService systemService) {
- this.systemService = systemService;
- }
- private static LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> resourceMap = null;
- public Collection<ConfigAttribute> getAllConfigAttributes() {
- // TODO Auto-generated method stub
- return null;
- }
- public boolean supports(Class<?> clazz) {
- // TODO Auto-generated method stub
- return true;
- }
- //加载所有资源与权限的关系
- private Map<String, String> getResource() {
- Map<String, String> resourceMap = new HashMap<String, String>();
- List<User> users = systemService.getAllUser();
- for(User user:users){
- for(Role role : user.getUserRoles()) {
- Set<Resource> resources = role.getRoleResources();
- for(Resource resource : resources) {
- String url = resource.getValue();
- if(!resourceMap.containsKey(url)) {
- resourceMap.put(url, role.getName());
- }else{
- String roleName = resourceMap.get(url);
- resourceMap.put(url, roleName+","+role.getName());
- }
- }
- }
- }
- return resourceMap;
- }
- private void loadResourceDefine(){
- resourceMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
- Map<String, String> resource = getResource();
- for(Map.Entry<String, String> entry:resource.entrySet()){
- Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
- configAttributes.add(new SecurityConfig(entry.getValue()));
- resourceMap.put(new AntPathRequestMatcher(entry.getKey()), configAttributes);
- }
- }
- //返回所请求资源所需要的权限
- public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
- HttpServletRequest request = ((FilterInvocation) object).getRequest();
- if(null==resourceMap){
- System.out.println("请求地址 " + ((FilterInvocation) object).getRequestUrl());
- loadResourceDefine();
- System.out.println("我需要的认证:"+resourceMap.toString());
- }
- for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : resourceMap.entrySet()) {
- if (entry.getKey().matches(request)) {
- return entry.getValue();
- }
- }
- return null;
- }
- }
MyAccessDecisionManager
- package com.yindejin.system;
- import java.util.Collection;
- import java.util.Iterator;
- import org.springframework.security.access.AccessDecisionManager;
- import org.springframework.security.access.AccessDeniedException;
- import org.springframework.security.access.ConfigAttribute;
- import org.springframework.security.authentication.InsufficientAuthenticationException;
- import org.springframework.security.core.Authentication;
- import org.springframework.security.core.GrantedAuthority;
- //3
- public class MyAccessDecisionManager implements AccessDecisionManager {
- public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
- if(configAttributes == null) {
- return;
- }
- //所请求的资源拥有的权限(一个资源对多个权限)
- Iterator<ConfigAttribute> iterator = configAttributes.iterator();
- while(iterator.hasNext()) {
- ConfigAttribute configAttribute = iterator.next();
- //访问所请求资源所需要的权限
- String needPermission = configAttribute.getAttribute();
- System.out.println("needPermission is " + needPermission);
- //用户所拥有的权限authentication
- for(GrantedAuthority ga : authentication.getAuthorities()) {
- if(needPermission.contains((ga.getAuthority()))) {
- return;
- }
- }
- }
- //没有权限让我们去捕捉
- throw new AccessDeniedException(" 没有权限访问!");
- }
- public boolean supports(ConfigAttribute attribute) {
- // TODO Auto-generated method stub
- return true;
- }
- public boolean supports(Class<?> clazz) {
- // TODO Auto-generated method stub
- return true;
- }
- }
MyAuthenticationManager
- package com.yindejin.system;
- import org.springframework.security.core.userdetails.UserDetails;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.core.userdetails.UsernameNotFoundException;
- import com.yindejin.system.service.ISystemService;
- import com.yindejin.util.StringUtils;
- import com.yindejin.vo.User;
- public class MyAuthenticationManager implements UserDetailsService {
- private ISystemService systemService;
- public void setSystemService(ISystemService systemService) {
- this.systemService = systemService;
- }
- @Override
- public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
- if(!StringUtils.isEmpty(userName)){
- throw new UsernameNotFoundException("用户名不能为空!");
- }
- User user = systemService.loginByUserName(userName);
- if (user == null) {
- throw new UsernameNotFoundException("用户名或密码错误!");
- }
- return user;
- }
- }
User
- package com.yindejin.vo;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import javax.persistence.Transient;
- import org.springframework.security.core.GrantedAuthority;
- import org.springframework.security.core.authority.GrantedAuthorityImpl;
- import org.springframework.security.core.userdetails.UserDetails;
- /**
- * User entity. @author MyEclipse Persistence Tools
- */
- public class User implements UserDetails {
- // Fields
- private Integer id;
- private String name;
- private String password = "123456";
- private Integer disabled = 0;
- private String email;
- public String getEmail() {
- return email;
- }
- public void setEmail(String email) {
- this.email = email;
- }
- private Set<Role> userRoles = new HashSet<Role>();
- @Transient
- private Map<String, List<Resource>> roleResources;
- // Constructors
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public Integer getDisabled() {
- return disabled;
- }
- public void setDisabled(Integer disabled) {
- this.disabled = disabled;
- }
- public Set<Role> getUserRoles() {
- return userRoles;
- }
- public void setUserRoles(Set<Role> userRoles) {
- this.userRoles = userRoles;
- }
- /** default constructor */
- public User() {
- }
- public String getUsername() {
- return name;
- }
- public boolean isAccountNonExpired() {
- return true;
- }
- public boolean isAccountNonLocked() {
- return true;
- }
- public boolean isCredentialsNonExpired() {
- return true;
- }
- public boolean isEnabled() {
- return this.disabled==0?true:false;
- }
- /**
- * @return the roleResources
- */
- public Map<String, List<Resource>> getRoleResources() {
- // init roleResources for the first time
- if(this.roleResources == null) {
- this.roleResources = new HashMap<String, List<Resource>>();
- for(Role role : this.userRoles) {
- String roleName = role.getName();
- Set<Resource> resources = role.getRoleResources();
- for(Resource resource : resources) {
- String key = roleName + "_" + resource.getType();
- if(!this.roleResources.containsKey(key)) {
- this.roleResources.put(key, new ArrayList<Resource>());
- }
- this.roleResources.get(key).add(resource);
- }
- }
- }
- return this.roleResources;
- }
- @SuppressWarnings("deprecation")
- @Override
- public Collection<GrantedAuthority> getAuthorities() {
- Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
- for(Role role : getUserRoles()){
- authSet.add(new GrantedAuthorityImpl(role.getName()));
- }
- return authSet;
- }
- }