spring security JDBC 数据库实现,5个表, 例子下载

摘要: 在前面用 srpng security  hibernate, mysql 做了一个简单的例子,仅仅用户和和角色,用户与角色的关系用数据库来保存,而对资源管理仍然用XML 配置方式来实现,对于某些特殊要求的项目来说,仍然没办法满足要求,于是就有了5张表的 Spring security  的扩展实现。在网上参考过别人很多文章以及博客,但总是没怎么成功过,关键是人家也不提供整个代码下载,所以很多细节不知道。好不容易试验出来,特地放出代码在本文最后下载。

在前面用 srpng security hibernate, mysql 做了一个简单的例子,仅仅用户和和角色,用户与角色的关系用数据库来保存,而对资源管理仍然用XML 配置方式来实现,对于某些特殊要求的项目来说,仍然没办法满足要求,于是就有了5张表的 Spring security 的扩展实现。在网上参考过别人很多文章以及博客,但总是没怎么成功过,关键是人家也不提供整个代码下载,所以很多细节不知道。好不容易试验出来,特地放出代码在本文最后下载。

创建 spring security 所要用到的表, 并初始化数据

spring security data schema free downlaod

重点在与对资源的拦截
由于提供了代码下载,所以有些地方就不必详细介绍了,而且在前面的文章中,也有讲到,所以重点是怎么拦截资源的实现.

package com.yihaomen.common.intercept;

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.beans.factory.annotation.Autowired;
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 MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

	// 与spring-security.xml里的myFilter的属性securityMetadataSource对应,
	// 其他的两个组件,已经在AbstractSecurityInterceptor定义
	@Autowired
	private FilterInvocationSecurityMetadataSource securityMetadataSource;

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {

		FilterInvocation fi = new FilterInvocation(request, response, chain);
		invoke(fi);

	}

	public Class getSecureObjectClass() {
		return FilterInvocation.class;
	}

	public void invoke(FilterInvocation fi) throws IOException,
			ServletException {
		// object为FilterInvocation对象
		// super.beforeInvocation(fi);源码
		// 1.获取请求资源的权限
		// 执行Collection attributes =
		// SecurityMetadataSource.getAttributes(object);
		// 2.是否拥有权限
		// this.accessDecisionManager.decide(authenticated, object, attributes);
		InterceptorStatusToken token = super.beforeInvocation(fi);

		try {
			fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
		} finally {
			super.afterInvocation(token, null);
		}

	}

	@Override
	public SecurityMetadataSource obtainSecurityMetadataSource() {
		return this.securityMetadataSource;
	}

	public void setSecurityMetadataSource(
			FilterInvocationSecurityMetadataSource securityMetadataSource) {
		this.securityMetadataSource = securityMetadataSource;
	}

	public void destroy() {

	}

	public void init(FilterConfig filterconfig) throws ServletException {

	}

}


另外还需要实现 FilterInvocationSecurityMetadataSource 接口 以及 AccessDecisionManager 来判断用户是否有访问资源的权限。在代码中注意如下的两个类 :

package com.yihaomen.comm.service;
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.access.SecurityConfig;

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 configAttributes)
	{
		if (configAttributes == null) {
			return;
		}
		//所请求的资源拥有的权限(一个资源对多个权限)
		Iterator ite = configAttributes.iterator();
		while (ite.hasNext()) {
			ConfigAttribute ca = ite.next();
			//访问所请求资源所需要的权限 
			String needRole = ((SecurityConfig) ca).getAttribute();
			System.out.println("needRole is " + needRole); 
			// ga 为用户所被赋予的权限。 needRole 为访问相应的资源应该具有的权限。
			for (GrantedAuthority ga : authentication.getAuthorities()) {

				if (needRole.trim().equals(ga.getAuthority().trim())) {
                    System.out.println("有相关的权限");
					return;
				}
			}			
			throw new AccessDeniedException("can not access this page");
		}
	}

	public boolean supports(ConfigAttribute arg0) {
		return true;
	}

	public boolean supports(Class arg0) {
		return true;
	}

}


package com.yihaomen.comm.service;

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

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import com.yihaomen.common.dao.ResourcesDao;
import com.yihaomen.common.domain.SysResource;

public class MyInvocationSecurityMetadataSourceService implements
		FilterInvocationSecurityMetadataSource {

	@Autowired
	private ResourcesDao resourcesDao;

	// resourceMap及为key-url,value-Collection,资源权限对应Map
	private static Map> resourceMap = null;

	public MyInvocationSecurityMetadataSourceService(ResourcesDao resourcesDao) {
		this.resourcesDao = resourcesDao;
		System.out.println("加载MyInvocationSecurityMetadataSourceService..."
				+ resourcesDao);
		loadResourceDefine();
	}

	// 加载所有资源与权限的关系
	private void loadResourceDefine() {
		if (resourceMap == null) {
			resourceMap = new HashMap>();
			List resources = resourcesDao.findAll();
			// 加载资源对应的权限
			for (SysResource resource : resources) {
				Collection auths = resourcesDao
						.loadRoleByResource(resource.getResource());
				System.out.println("权限=" + auths);
				resourceMap.put(resource.getResource(), auths);
			}
		}
	}

	// 加载所有资源与权限的关系
	public Collection getAttributes(Object object)
			throws IllegalArgumentException {
		// object是一个URL,被用户请求的url
		String requestUrl = ((FilterInvocation) object).getRequestUrl();
		System.out.println("requestUrl is " + requestUrl);

		int firstQuestionMarkIndex = requestUrl.indexOf("?");

		if (firstQuestionMarkIndex != -1) {
			requestUrl = requestUrl.substring(0, firstQuestionMarkIndex);
		}

		if (resourceMap == null) {
			loadResourceDefine();
		}
		
		Iterator ite = resourceMap.keySet().iterator();

		while (ite.hasNext()) {
			String resURL = ite.next();
			if (resURL.equals(requestUrl)) {
				return resourceMap.get(resURL);
			}
		}
		
		return null;
	}

	public boolean supports(Class arg0) {
		return true;
	}

	public Collection getAllConfigAttributes() {
		return null;
	}

}


运行程序,这样就能实现对数据库中配置的资源的拦截,有权限的就能访问,否则403错误. 整个代码下载:
spring security database source code free download

参考的文章如下,原来来自百度文库:spring security document

上一篇: 写sql语句时应注意的事项
下一篇: 自定义ehcache工具类实现缓存
 评论 ( What Do You Think )
名称
邮箱
网址
评论
验证
   
 

 


  • 微信公众号

  • 我的微信

站点声明:

1、一号门博客CMS,由Python, MySQL, Nginx, Wsgi 强力驱动

2、部分文章或者资源来源于互联网, 有时候很难判断是否侵权, 若有侵权, 请联系邮箱:summer@yihaomen.com, 同时欢迎大家注册用户,主动发布无版权争议的 文章/资源.

3、鄂ICP备14001754号-3, 鄂公网安备 42280202422812号