spring security 登录、权限管理配置

登录流程

1)容器启动(MySecurityMetadataSource:loadResourceDefine加载系统资源与权限列表)
 2)用户发出请求
 3)过滤器拦截(MySecurityFilter:doFilter)
 4)取得请求资源所需权限(MySecurityMetadataSource:getAttributes)
 5)匹配用户拥有权限和请求权限(MyAccessDecisionManager:decide),如果用户没有相应的权限,

     执行第6步,否则执行第7步。
 6)登录
 7)验证并授权(MyUserDetailServiceImpl:loadUserByUsername)


1、web.xml中加入过滤器

<!-- SpringSecurity 核心过滤器配置 -->
<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>


2、新建spring-security.xml文件

<?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.xsd
	http://www.springframework.org/schema/security
	http://www.springframework.org/schema/security/spring-security.xsd">

	<!-- entry-point-ref 配置自定义登录 -->
	<http use-expressions="true" entry-point-ref="authenticationProcessingFilterEntryPoint">
		
		<!-- 登出配置 -->
		<logout logout-url="/j_spring_security_logout" logout-success-url="/login" />

		<access-denied-handler error-page="/noPower" />
		
		<!-- 过滤不被拦截的请求 -->
		<intercept-url pattern="/login*" access="permitAll" />
		<intercept-url pattern="/resources/**" access="permitAll" />
		
		<!-- 只有权限才能访问的请求 -->
		<intercept-url pattern="/admin/**" access="isAuthenticated()" />

		<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER" />
		<custom-filter ref="securityFilter" before="FILTER_SECURITY_INTERCEPTOR" />

	</http>

	<beans:bean id="loginFilter"
		class="cn.com.abel.test.service.security.MyUsernamePasswordAuthenticationFilter">
		
		<!-- 登录提交处理 -->
		<beans:property name="filterProcessesUrl" value="/j_spring_security_check"></beans:property>
		
		<!-- 登录成功跳转 -->
		<beans:property name="authenticationSuccessHandler"
			ref="loginLogAuthenticationSuccessHandler"></beans:property>
		
		<!-- 设置登录失败的网址 -->
		<beans:property name="authenticationFailureHandler"
			ref="simpleUrlAuthenticationFailureHandler"></beans:property>
		
		<!-- 用户拥有权限 -->	
		<beans:property name="authenticationManager" ref="myAuthenticationManager"></beans:property>
	</beans:bean>

	<beans:bean id="loginLogAuthenticationSuccessHandler"
		class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
		<beans:property name="defaultTargetUrl" value="/admin/index"></beans:property>
	</beans:bean>
	<beans:bean id="simpleUrlAuthenticationFailureHandler"
		class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
		<beans:property name="defaultFailureUrl" value="/login"></beans:property>
	</beans:bean>

	<authentication-manager alias="myAuthenticationManager">
		<authentication-provider user-service-ref="myUserDetailServiceImpl">
			<password-encoder ref="encoder" />
		</authentication-provider>
	</authentication-manager>

	<beans:bean id="myUserDetailServiceImpl"
		class="cn.com.abel.test.service.security.AdminUserDetailServiceImpl">
	</beans:bean>

	<beans:bean id="authenticationProcessingFilterEntryPoint"
		class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
		<beans:property name="loginFormUrl" value="/login"></beans:property>
	</beans:bean>

	<!-- 认证过滤器 -->
	<beans:bean id="securityFilter"
		class="cn.com.abel.test.service.security.MySecurityFilter">
		<!-- 用户拥有的角色 -->
		<beans:property name="authenticationManager" ref="myAuthenticationManager" />
		<!-- 用户是否拥有所请求资源的权限 -->
		<beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />
		<!-- 资源与角色的对应关系 -->
		<beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />
		<!-- <beans:property name="rejectPublicInvocations" value="true"/> -->

	</beans:bean>
	
	<beans:bean id="myAccessDecisionManager" class="myAccessDecisionManager"></beans:bean>
	
	<beans:bean id="mySecurityMetadataSource"
		class="cn.com.abel.test.service.security.MySecurityMetadataSource">
		<beans:constructor-arg>
			<beans:ref bean="resourceService" />
		</beans:constructor-arg>
	</beans:bean>

	<beans:bean id="encoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"></beans:bean>
  
</beans:beans>


3、MyUsernamePasswordAuthenticationFilter.java

package cn.com.abel.test.service.security;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

		if (!request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
		}

		String username = obtainUsername(request);
		String password = obtainPassword(request);

		if (username == null) {
			username = "";
		}

		if (password == null) {
			password = "";
		}

		username = username.trim();

		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);

//		//登录验证码,如需要开启把下面注释去掉则可
//		String authCode = StringUtils.defaultString(request.getParameter("authCode"));
//		if(!AdwImageCaptchaServlet.validateResponse(request, authCode)){
//			throw new AuthenticationServiceException("validCode.auth.fail");
//		}

		return this.getAuthenticationManager().authenticate(authRequest);
	}
}

4、MySecurityFilter.java

package cn.com.abel.test.service.security;

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 {
		// object为FilterInvocation对象
		//1.获取请求资源的权限
		//执行Collection<ConfigAttribute> attributes = SecurityMetadataSource.getAttributes(object);
		//2.是否拥有权限
		//获取安全主体,可以强制转换为UserDetails的实例
		//1) UserDetails
		// Authentication authenticated = authenticateIfRequired();
		//this.accessDecisionManager.decide(authenticated, object, attributes);
		//用户拥有的权限
		//2) GrantedAuthority
		//Collection<GrantedAuthority> authenticated.getAuthorities()
		//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;
	}
}

5、AdminUserDetailServiceImpl.java

package cn.com.abel.test.service.security;

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

import org.springframework.beans.factory.annotation.Autowired;
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 cn.com.abel.test.model.RoleModel;
import cn.com.abel.test.model.MemberModel;
import cn.com.abel.test.service.RoleService;
import cn.com.abel.test.service.MemberService;

public class AdminUserDetailServiceImpl implements UserDetailsService {
	@Autowired
	private MemberService memberService;
	@Autowired
	RoleService roleService;
 
	//登录验证
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		
	 
		MemberModel member = memberService.getUserDetailsByUserName(username);
		
		if(member==null){
			throw new UsernameNotFoundException("member "+username +" not found.");
		}
		Set<GrantedAuthority> grantedAuths = obtionGrantedAuthorities(member);

                //封装成spring security的user
                User userdetail = new User(user.getUserName(), user.getPassword(),
                true, // 账号状态 0 表示停用 1表示启用
                true, true, true, grantedAuths // 用户的权限
                );
                return userdetail;
	}
	
	//取得用户的权限
	private Set<GrantedAuthority> obtionGrantedAuthorities(MemberModel member) {
		
		Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
		
		List<RoleModel> roles = roleService.getRoleByUser(member)<span style="font-family:Arial, Helvetica, sans-serif;">;</span>
		if(roles!=null){
			for(RoleModel role : roles) {
				authSet.add(new SimpleGrantedAuthority(role.getRoleCode().trim()));
			}
		}
 
		return authSet;
	}
	
}

6、MyAccessDecisionManager.java

package cn.com.abel.test.service.security;

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;

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.equals(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;
	}
	
}


7、MySecurityMetadataSource.java

package cn.com.abel.test.service.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
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.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import cn.com.abel.test.model.RoleModel;
import cn.com.abel.test.service.ResourceService;

public class MySecurityMetadataSource  implements FilterInvocationSecurityMetadataSource,InitializingBean {

	
	private static final String AUTH_NO_ROLE =" __AUTH_NO_ROLE__";
	
	private ResourceService resourceService;
	
	public MySecurityMetadataSource(ResourceService resourceService) {
		this.resourceService = resourceService;
	}

	private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return null;
	}

	public boolean supports(Class<?> clazz) {
		return true;
	}
	private void loadResourceDefine() {
		if(resourceMap == null) {
			resourceMap = new ConcurrentHashMap<String, Collection<ConfigAttribute>>();
		}else{
			resourceMap.clear();
		}
		
		Map<String,List<RoleModel>> resourceRoleMap = resourceService.getAllResourceRole();
		
		for (Entry<String,List<RoleModel>> entry : resourceRoleMap.entrySet()) {
			String url = entry.getKey();
			List<RoleModel> values = entry.getValue();
			
			Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
			for(RoleModel secRoleModel : values){
				ConfigAttribute configAttribute = new SecurityConfig(StringUtils.defaultString(secRoleModel.getRoleCode(),AUTH_NO_ROLE));
				configAttributes.add(configAttribute);
			}
			resourceMap.put(url, configAttributes);
		}
	}
	public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
		
		HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();  
 
		TreeMap<String, Collection<ConfigAttribute>> attrMap = new TreeMap<String, Collection<ConfigAttribute>>(resourceMap);
		
		Iterator<String> ite = attrMap.keySet().iterator();  
		
		RequestMatcher urlMatcher = null;  

		Collection<ConfigAttribute> attrSet = new HashSet<ConfigAttribute>();
		//match all of /admin/**  a/b/**
		while (ite.hasNext()) {  
			
			String resURL = ite.next();  
			urlMatcher = new AntPathRequestMatcher(resURL);

			if (urlMatcher.matches(request)||StringUtils.equals(request.getRequestURI(),resURL)) {  
				attrSet.addAll(attrMap.get(resURL));  
			}  
		}  

		if(!attrSet.isEmpty()){
			return attrSet;
		}
		return null;
	}
 
	@Override
	public void afterPropertiesSet() throws Exception {
		loadResourceDefine() ;
	}
	
}

8、ResourceService.java

此类是为从数据库获取系统中的资源所属的角色,根据自己的数据表自行编写。

package cn.com.abel.test.service;

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

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.com.abel.test.mapper.ResourceModelMapper;
import cn.com.abel.test.mapper.RoleModelMapper;
import cn.com.abel.test.mapper.RoleResourcetModelMapper;
import cn.com.abel.test.model.ResourceModel;
import cn.com.abel.test.model.ResourceModelCriteria;
import cn.com.abel.test.model.RoleModel;
import cn.com.abel.test.model.RoleModelCriteria;
import cn.com.abel.test.model.RoleResourcetModel;
import cn.com.abel.test.model.RoleResourcetModelCriteria;

@Service
public class ResourceService {
	
	@Autowired
	ResourceModelMapper resourceModelMapper;
	
	@Autowired
	RoleModelMapper roleMapper;
	
	@Autowired
	RoleResourcetModelMapper  roleResMapper;
	
	/**
	 * 获取各个资源(url)对应的角色
	 * @return
	 */
	public Map<String,List<RoleModel>> getAllResourceRole(){
		
		 Map<String,List<RoleModel>> resultMap = new HashMap<String,List<RoleModel>>();
		 
		ResourceModelCriteria secResourceModelExample = new ResourceModelCriteria();
		List<ResourceModel> resourceList = resourceModelMapper.selectByExample(secResourceModelExample);
		
		if(CollectionUtils.isNotEmpty(resourceList)){
			for(ResourceModel secResourceModel : resourceList){
				RoleModelCriteria roleCriteria = new RoleModelCriteria();
				roleCriteria.createCriteria().andIdIn(getRoleIdsByResourceId(secResourceModel.getId()));
				List<RoleModel> roleList = roleMapper.selectByExample(roleCriteria);
				resultMap.put(secResourceModel.getValue(), roleList);
				
			}
		}
	 
		return resultMap;
	}
	
	public List<Integer> getRoleIdsByResourceId(Integer resourceId){
		List<Integer> roleIds = new ArrayList<Integer>();
		
		RoleResourcetModelCriteria criteria = new RoleResourcetModelCriteria();
		criteria.createCriteria().andResourceIdEqualTo(resourceId);
		List<RoleResourcetModel> list = roleResMapper.selectByExample(criteria);
		if(CollectionUtils.isNotEmpty(list)){
			for(RoleResourcetModel model : list){
				roleIds.add(model.getRoleId());
			}
		}
		
		HashSet<Integer> h  =   new  HashSet<Integer>(roleIds);     
		roleIds.clear();     
		roleIds.addAll(h);   
		return roleIds;
	}
}


最后附上数据表的SQL:

CREATE TABLE `auth_resource` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(100) NULL DEFAULT NULL COMMENT '资源名称',
	`value` VARCHAR(100) NULL DEFAULT NULL COMMENT '资源值',
	`summary` VARCHAR(1000) NULL DEFAULT NULL COMMENT '资源描述',
	`updated_time` DATETIME NULL DEFAULT NULL,
	`updated_user` VARCHAR(100) NULL DEFAULT NULL,
	PRIMARY KEY (`id`)
)
COMMENT='资源访问表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

CREATE TABLE `auth_role` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`role_name` VARCHAR(100) NULL DEFAULT NULL COMMENT '角色名称',
	`role_code` VARCHAR(100) NULL DEFAULT NULL COMMENT '角色代码',
	`updated_time` DATETIME NULL DEFAULT NULL,
	`updated_user` VARCHAR(100) NULL DEFAULT NULL,
	PRIMARY KEY (`id`)
)
COMMENT='角色表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

CREATE TABLE `role_resource` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`role_id` INT(11) NOT NULL,
	`resource_id` INT(11) NOT NULL,
	PRIMARY KEY (`id`),
	UNIQUE INDEX `role_id_resource_id` (`role_id`, `resource_id`)
)
COMMENT='资源角色关联表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

CREATE TABLE `member` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`user_name` VARCHAR(100) NULL DEFAULT NULL,
	`nick` VARCHAR(100) NULL DEFAULT NULL,
	`password` VARCHAR(100) NULL DEFAULT NULL,
	`sex` INT(11) NULL DEFAULT NULL,
	`birthday` DATE NULL DEFAULT NULL,
	`mobile` VARCHAR(50) NULL DEFAULT NULL,
	`email` VARCHAR(50) NULL DEFAULT NULL,
	`address` VARCHAR(512) NULL DEFAULT NULL,
	`regip` VARCHAR(100) NULL DEFAULT NULL,
	`created_time` DATETIME NULL DEFAULT NULL,
	PRIMARY KEY (`id`)
)
COMMENT='用户表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2;

CREATE TABLE `member_role` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`member_id` INT(11) NOT NULL,
	`role_id` INT(11) NOT NULL,
	PRIMARY KEY (`id`),
	UNIQUE INDEX `member_id_role_id` (`member_id`, `role_id`)
)
COMMENT='用户角色关联表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

完整代码下载(包含数据库): http://download.csdn.net/download/rongku/9931455



  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值