Spring Security权限管理

       Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

1、权限管理数据库的设计

权限管理包含五个表:user、role、user_role、resource、role_resource,它们的关系如下图:

Spring Security权限管理_第1张图片

Mysql建库的脚本如下:

CREATE DATABASE `test`;
USE `test`;
/*Table structure for table `resource` */
DROP TABLE IF EXISTS `resource`;
CREATE TABLE `resource` (
  `resource_id` bigint(32) NOT NULL AUTO_INCREMENT,
  `name` varchar(64) NOT NULL,
  `url` varchar(256) NOT NULL,
  PRIMARY KEY (`resource_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

/*Data for the table `resource` */
insert  into `resource`(`resource_id`,`name`,`url`) values (1,'common_index','/myPage/myPage.jsp'),(2,'admin_index','/admin/admin.jsp');

/*Table structure for table `role` */
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `role_id` bigint(32) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Data for the table `role` */
insert  into `role`(`role_id`,`name`) values (1,'common_user'),(2,'admin');

/*Table structure for table `role_resource` */
DROP TABLE IF EXISTS `role_resource`;
CREATE TABLE `role_resource` (
  `role_resource_id` bigint(32) NOT NULL AUTO_INCREMENT,
  `role_id` bigint(32) DEFAULT NULL,
  `resource_id` bigint(32) DEFAULT NULL,
  PRIMARY KEY (`role_resource_id`),
  KEY `role_resource_fk_roleId` (`role_id`),
  KEY `role_resource_fk_resourceId` (`resource_id`),
  CONSTRAINT `role_resource_fk_roleId` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`),
  CONSTRAINT `role_resource_fk_resourceId` FOREIGN KEY (`resource_id`) REFERENCES `resource` (`resource_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

/*Data for the table `role_resource` */
insert  into `role_resource`(`role_resource_id`,`role_id`,`resource_id`) values (1,1,1),(2,2,2);

/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `user_id` bigint(32) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL,
  `password` varchar(32) NOT NULL,
  `enable` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

/*Data for the table `user` */
insert  into `user`(`user_id`,`username`,`password`,`enable`) values (1,'li','e10adc3949ba59abbe56e057f20f883e',1),(2,'admin','e10adc3949ba59abbe56e057f20f883e',1);

/*Table structure for table `user_role` */
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
  `user_role_id` bigint(32) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(32) DEFAULT NULL,
  `role_id` bigint(32) DEFAULT NULL,
  PRIMARY KEY (`user_role_id`),
  KEY `user_role_fk_userId` (`user_id`),
  KEY `user_role_fk_roleId` (`role_id`),
  CONSTRAINT `user_role_fk_userId` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`),
  CONSTRAINT `user_role_fk_roleId` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Data for the table `user_role` */
insert  into `user_role`(`user_role_id`,`user_id`,`role_id`) values (1,1,1),(2,2,2),(3,2,1);

2、Spring Security权限管理流程图

Spring Security权限管理_第2张图片

3、系统程序结构

Spring Security权限管理_第3张图片

4、核心类

4.1 SecurityMetadataSourceService

package com.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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 com.bean.RoleResource;
import com.service.UserService;

/**
 * Spring security 处理用户权限列表查询组合实现类
 * 资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色去访问,形成权限列表
 * @author brushli
 * @date 2014-09-02
 */
public class SecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {
	
	private UserService userService;

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

    private static Map> resourceMap = null;  
  
    /**
     * 加载所有角色与权限的关系  
     */
	private void loadAllResources() {  
        if(resourceMap == null) {
            resourceMap = new HashMap>();  
            //得所有角色并且得到这些角色各自拥有什么功能权限
            List roleResourceList = null;
			try {
				roleResourceList = userService.getAllRoleResources();
			} catch (Exception e) {
				e.printStackTrace();
			}
			if(roleResourceList != null && !roleResourceList.isEmpty()){
				for (RoleResource roleResource : roleResourceList) {  
					//先检查该角色是否已加入过权限列表,如果是,只需要读取出来,然后继续添加功能权限;如果否,新增该角色的权限列表
					Collection configAttributes = resourceMap.get(roleResource.getUrl());
					if(configAttributes == null){
						configAttributes = new ArrayList();  
					}
					
					ConfigAttribute configAttribute = new SecurityConfig(roleResource.getRoleName());
					configAttributes.add(configAttribute);  
					
					resourceMap.put(roleResource.getUrl(), configAttributes);  
				}
			}
        }  
    }  
    
    /**
     * 返回所请求资源所需要的权限,根据roleName得到模块
     */
    public Collection getAttributes(Object object) throws IllegalArgumentException {  
        String requestUrl = ((FilterInvocation) object).getRequestUrl();  
        if(resourceMap == null) {  
        	loadAllResources();  
        }  
        //判断请求是否有明文参数,如果是,截取参数前的url,不是则直接利用请求url
        if(requestUrl.indexOf("?") != -1){
        	requestUrl = requestUrl.substring(0, requestUrl.indexOf("?"));
        }
        return resourceMap.get(requestUrl);  
    }
    
    public Collection getAllConfigAttributes() {  
        return null;  
    }  
  
    public boolean supports(Class clazz) {  
        return true;  
    }  
}

4.2 AccessDecisionManagerService

package com.service.impl;

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;

/**
 * spring security决策管理器
 * @author brushli
 * @date 2014-09-02
 */
public class AccessDecisionManagerService implements AccessDecisionManager{

    //In this method, need to compare authentication with configAttributes.
    // 1, A object is a URL, a filter was find permission configuration by this URL, and pass to here.
    // 2, Check authentication has attribute in permission configuration (configAttributes)
    // 3, If not match corresponding authentication, throw a AccessDeniedException.
    public void decide(Authentication authentication, Object object,
            Collection configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {
    	
    	if(configAttributes == null) {  
            return;  
        }  
        //所请求的资源拥有的权限(一个资源对多个权限)  
        Iterator iterator = configAttributes.iterator();  
        while(iterator.hasNext()) {  
            ConfigAttribute configAttribute = iterator.next();  
            //访问所请求资源所需要的权限  
            String functionId = configAttribute.getAttribute();  
            //用户所拥有的权限authentication  
            for(GrantedAuthority ga : authentication.getAuthorities()) {  
                if(functionId.equals(ga.getAuthority())) {  
                    return;  //放行
                }  
            }  
        }  
        //没有权限  
        throw new AccessDeniedException(" 没有权限访问! ");  
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class clazz) {
        return true;
    }
}

4.3 WebUserDetailsService

package com.service.impl;

import java.util.HashSet;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.bean.Role;
import com.bean.User;
import com.bean.UserLoginDetails;
import com.service.UserService;


/**
 * 用户登录是准备阶段的业务逻辑
 * 用户登陆时会用username去用户表中查出用户的资料,包括密码,再比较输入的密码和用户表中的密码
 * @author brushli
 * @date 2014-09-02
 */
public class WebUserDetailsService implements UserDetailsService {
	protected static final Logger logger = LoggerFactory.getLogger(WebUserDetailsService.class);
	
	private UserService userService;

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		boolean accountNonExpired = true;  
        boolean credentialsNonExpired = true;  
        boolean accountNonLocked = true;
        boolean enabled = true;
        
        User user = null;
        try {
			user = userService.getUserByUsername(username);
		} catch (Exception e) {
			e.printStackTrace();
		}
        
        if(user == null){
			throw new UsernameNotFoundException("User account : " + username + " not found!");
		}
        
        //封装该用户具有什么角色
        Set authorities = new HashSet(); 
        if(user.getRoles() != null && !user.getRoles().isEmpty()){
        	for(Role role : user.getRoles()){
        		GrantedAuthority ga = new SimpleGrantedAuthority(role.getName());
        		authorities.add(ga);       
        	}
        }
        
        UserLoginDetails userLoginDetails =  new UserLoginDetails(user.getUsername(), user.getPassword(), authorities, accountNonExpired, accountNonLocked, credentialsNonExpired, enabled);

        return userLoginDetails;
	}
}

5、配置文件

5.1 web.xml



	security
	
		index.jsp
	

	
		contextConfigLocation
		
			classpath*:applicationContext-datasource.xml,classpath*:applicationContext-security.xml
		
	
	
	
		encoding-filter
		org.springframework.web.filter.CharacterEncodingFilter
		
			encoding
			UTF-8
		
	
	
		encoding-filter
		/*
	

	
	
		springSecurityFilterChain
		org.springframework.web.filter.DelegatingFilterProxy
	
	
		springSecurityFilterChain
		/*
	

	
		org.springframework.web.context.ContextLoaderListener
	
	
	
		org.springframework.security.web.session.HttpSessionEventPublisher
	
	
	
		springServlet
		org.springframework.web.servlet.DispatcherServlet
		
			contextConfigLocation
			classpath*:applicationContext-servlet.xml
		
		1
	
	
		springServlet
		*.do
	
	
	
		60
	

5.2 applicationContext-security.xml



	
	
	
	

	
	
		
		
		
		
		
		
				
		
				
        
            
        
		        
           
        
        
	
			
	  
	  
		  
		  
		  
	
	
	  
	
	    
	
	
	
	
			
		    
		
	
	
	  
	 
	

5.3 applicationContext-datasource.xml

  


	
		
		
		
		
		
		
		
	

	
		
	

	
		
			
			
			
			
			
			
		
	
	
	
       
       
	
	
	
		
	
	
	
		
	
	
	
		
	
	
	
	
	
	
	
		
	
	

6、系统的运行效果

待续...

7、系统的下载地址

http://download.csdn.net/detail/brushli/7865697


 

你可能感兴趣的:(spring,java)