springMVC+mybatis+spring security<三>:使用数据库管理资源

实际使用中,资源都是保存在数据库中,而不是在XML中进行配置。

使用数据库管理资源时,需要实现FilterInvocationSecurityMetadataSource接口:

public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource, InitializingBean {

	private boolean expire = false;
	
	private final static List<ConfigAttribute> NULL_CONFIG_ATTRIBUTE = Collections.emptyList();

	private Map<String, Collection<ConfigAttribute>> requestMap;

	private AntPathMatcher urlMatcher = new AntPathMatcher();

	@Autowired
	private SysResourceService sysResourceService;

	/**
	 * 获取所有权限集合
	 */
	@Override
	public Collection<ConfigAttribute> getAllConfigAttributes() {
		Set<ConfigAttribute> set = new HashSet<ConfigAttribute>();
		for (Map.Entry<String, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {
			set.addAll(entry.getValue());
		}
		return set;
	}

	/**
	 * 根据request请求获取访问资源所需权限
	 */
	@Override
	public Collection<ConfigAttribute> getAttributes(Object obj) throws IllegalArgumentException {
		//刷新资源
		if(isExpire()){
			this.requestMap.clear();
			expire = false;
		}
		//若map为空,则重新加载
		if(this.requestMap==null || this.requestMap.isEmpty()){
			this.requestMap = bindRequestMap();
		}
		
		String URL = ((FilterInvocation) obj).getRequestUrl();
		if (URL.contains("&")) {
			URL = URL.substring(0, URL.indexOf("&"));
		}
		Collection<ConfigAttribute> attrs = NULL_CONFIG_ATTRIBUTE;
		for (Map.Entry<String, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {
			if (urlMatcher.match(URL, entry.getKey())) {
				attrs = entry.getValue();
				break;
			}
		}
		return attrs;
	}

	@Override
	public boolean supports(Class<?> arg0) {
		return FilterInvocation.class.isAssignableFrom(arg0);
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		this.requestMap = this.bindRequestMap();

	}

	protected Map<String, Collection<ConfigAttribute>> bindRequestMap() {
		Map<String, Collection<ConfigAttribute>> map = new LinkedHashMap<String, Collection<ConfigAttribute>>();

		Map<String, String> sourceMap = this.loadResouece();

		for (Map.Entry<String, String> entry : sourceMap.entrySet()) {
			String key = entry.getKey();
			Collection<ConfigAttribute> attr = new ArrayList<ConfigAttribute>();
			attr = SecurityConfig.createListFromCommaDelimitedString(entry.getValue());
			map.put(key, attr);
		}

		return map;
	}

	/**
	 * 从数据库中加载权限和资源的对应列表
	 * 
	 * @return
	 */
	private Map<String, String> loadResouece() {
		Map<String, String> map = new LinkedHashMap<String, String>();
		List<SysResource> list = sysResourceService.getAllResRole();
		if (list != null && list.size() > 0) {
			for (SysResource r : list) {
				String path = r.getResourcePath();
				String code = r.getGroupCode();
				if (map.containsKey(path)) {
					String existCode = map.get(path);
					map.put(path, existCode + "," + code);
				} else {
					map.put(path, code);
				}
			}
		}
		return map;
	}

	public boolean isExpire() {
		return expire;
	}
	public void expireNow(){
		this.expire = true;
	}
}

以上代码主要的做法就是:

  (1)将资源从数据库中查出来,并和其对应的角色做关联,封装到Map<String, Collection<ConfigAttribute>>中;

  (2)每次请求到达过滤器后,根据请求的URL去map中匹配对应的权限(即角色)。


在security的配置文件中做相应配置:自己实现的过滤器要在security的之前执行

<!-- 自定义过滤器,在security的过滤器之前执行 -->
<custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/>
</pre><pre name="code" class="html"><beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
	<beans:property name="securityMetadataSource" ref="securityMetadataSource"></beans:property>
	<beans:property name="accessDecisionManager" ref="accessDecisionManager"></beans:property>
	<beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
</beans:bean>

以上步骤完成后,就可以实现对资源URL的过滤。

在实际使用时,还需要注意到的一个问题就是,在每次分配完权限之后,需重启系统才能生效。这是因为该类初始化之后将资源map加载到了内存中,数据库发生了变化,但内存并没有刷新。

基于以上原理,解决该问题的办法就是:在每次分配完权限之后,重新加载map,这也是代码中加入expire属性的原因。

      // 数据库权限发生变化,需要刷新内存
	WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(request
			.getServletContext());
	MySecurityMetadataSource source = (MySecurityMetadataSource)wac.getBean("securityMetadataSource");
	source.expireNow();

这样可以做到即使不用LogOut更不用重启项目,也可以动态的刷新权限资源。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值