shrio自定义filter实现权限与角色复杂逻辑访问权限判断

首先说明一点shiro框架我只懂得很少,大部分代码是从网上down的,考虑到shiro url授权配置不方便的地方,结合自己做的东西谈谈感受。大家轻拍。如果shrio有更新的解决方案或者大家有更好的方法可以多多指教。

废话不多说。

前提:我定义了两个权限 user:add 、user:add 和一个角色role-admin

需求: 访问/user/user  这个链接资源需要有(user:add  and user:edit11 ) or role-admin , 其中and 和 or是关系逻辑,

意思就是用户同时有两个权限user:add和user:edit11 或者单独有角色role-admin,可以访问/user/user。

贴上我的shiro配置,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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.1.xsd">
	<!-- 启用shrio授权注解拦截方式 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 装配 securityManager -->
		<property name="securityManager" ref="securityManager" />
		<!-- 配置登陆页面 -->
		<property name="loginUrl"
			value="http://localhost:8080/wemall/wemall-business-web/user/nolog" />
		<!-- 登陆成功后的一面 -->
		<property name="successUrl" value="/jsp/success.jsp" />
		<property name="unauthorizedUrl"
			value="http://localhost:8080/wemall/wemall-business-web/user/unauthorized" />
		<!-- 具体配置需要拦截哪些 URL, 以及访问对应的 URL 时使用 Shiro 的什么 Filter 进行拦截. -->
		<!-- <property name="filterChainDefinitions"> <value> /index.jsp=anon /jsp/success.jsp=anon 
			/jsp/fail.jsp=anon /user/user = perms[user:view] /jsp/admin.jsp = roles[admin] 
			/logout = logout </value> </property> -->
		<property name="filters">
			<map>
				<entry key="rolesor">
					<bean class="com.wemall.shrio.filterchaindef.CustomRolesAuthorizationFilter" />
				</entry>
				<entry key="all">
					<bean class="com.wemall.shrio.filterchaindef.AllAuthorizationFilter" />
				</entry>
			</map>
		</property>
	</bean>
	<!-- 权限资源配置 -->
	<bean id="filterChainDefinitionsService"
		class="com.wemall.shrio.filterchaindef.SimpleFilterChainDefinitionsService">
		<property name="definitions">
			<value>
				<!-- /index.jsp=anon /jsp/success.jsp=anon /jsp/fail.jsp=anon /jsp/admin.jsp 
					= roles[admin] -->
				<!-- 此处改为从数据库读取 -->
				/logout = logout
			</value>
		</property>
	</bean>
	<!-- 配置缓存管理器 -->
	<!-- <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> 
		指定 ehcache 的配置文件 <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml" 
		/> </bean> -->
	<!-- 配置进行授权和认证的 Realm -->
	<!-- <bean id="myRealm" class="com.wemall.user.realm.UserRealm"> <property 
		name="userService" ref="userService" /> </bean> -->
	<!-- <bean id="userService" class="com.gray.user.service.impl.UserServiceImpl" 
		/> -->
	<!-- 配置 Shiro 的 SecurityManager Bean. -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="myRealm" />
		<property name="sessionMode" value="native">
		</property>
	</bean>
	<!-- 配置 Bean 后置处理器: 会自动的调用和 Spring 整合后各个组件的生命周期方法. -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
</beans>  

首先看,SimpleFilterChainDefinitionsService,资源配置,从数据库读取,采用的是下边的类
com.wemall.shrio.filterchaindef.SimpleFilterChainDefinitionsService

	<!-- 权限资源配置 -->
	<bean id="filterChainDefinitionsService"
		class="com.wemall.shrio.filterchaindef.SimpleFilterChainDefinitionsService">
		<property name="definitions">
			<value>
				<!-- /index.jsp=anon /jsp/success.jsp=anon /jsp/fail.jsp=anon /jsp/admin.jsp 
					= roles[admin] -->
				<!-- 此处改为从数据库读取 -->
				/logout = logout
			</value>
		</property>
	</bean>

表结构


具体类代码SimpleFilterChainDefinitionsService

package com.wemall.shrio.filterchaindef;

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

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import com.wemall.shriourl.dao.ShrioUrlDao;
import com.wemall.shriourl.entity.ShrioUrl;

/**
 * 
 * 加载第三方角色资源配置服务类
 * 
 * @author shadow
 * 
 */
public class SimpleFilterChainDefinitionsService extends AbstractFilterChainDefinitionsService {
	private final static Logger log = Logger.getLogger(SimpleFilterChainDefinitionsService.class);
	@Autowired
	private ShrioUrlDao shrioUrlDao;

	@Override
	public Map<String, String> initOtherPermission() {
		// extend to load other permission
		Map<String, String> shrioUrlMap = new HashMap<String, String>();
		List<ShrioUrl> shrioUrlList = shrioUrlDao.selectAllShrioUrl();
		if (shrioUrlList != null && shrioUrlList.size() > 0) {
			for (ShrioUrl shrioUrl : shrioUrlList) {
				if (shrioUrl.getUrl() == null || shrioUrl.getUrl().isEmpty()) {
					log.debug("sys_shrio_url表中id为" + shrioUrl.getId() + "的url字段为空,不进行过滤");
					continue;
				}
				if (shrioUrl.getFiltername() == null || shrioUrl.getFiltername().isEmpty()) {
					log.debug("sys_shrio_url表中id为" + shrioUrl.getId() + "的filtername字段为空,不进行过滤");
					continue;
				}
				if (shrioUrl.getDef() == null || shrioUrl.getDef().isEmpty()) {
					log.debug("sys_shrio_url表中id为" + shrioUrl.getId() + "的def字段为空,不进行过滤");
					continue;
				}
				shrioUrlMap.put(shrioUrl.getUrl(), shrioUrl.getFiltername() + "[" + shrioUrl.getDef() + "]");
			}
		}
		return shrioUrlMap;
	}

}

大体上就是返回个map,里边放着过滤的形式,比如我的返回就是 key =/user/user 

,value = all [( perm-user:add and perm-user:edit11 ) or role-admin],这个东西就会自动加到filterChainDefinitionsService的definitions里, all就对应了配置文件中的

				<entry key="all">
					<bean class="com.wemall.shrio.filterchaindef.AllAuthorizationFilter" />
				</entry>

这就意味着访问/user/user,就要走all这个过滤器,过滤器需要对( perm-user:add and perm-user:edit11 ) or role-admin这个公式进行判断,是否可以访问。这里的perm-和role-表示是权限还是角色,这样一个公式就既支持权限又支持角色了,下面代码也会对这个perm-和role-的形式进行解析。

filter代码:

package com.wemall.shrio.filterchaindef;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.log4j.Logger;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;

// AuthorizationFilter抽象类事项了javax.servlet.Filter接口,它是个过滤器。    
public class AllAuthorizationFilter extends AuthorizationFilter {

	private final static Logger log = Logger.getLogger(AllAuthorizationFilter.class);

	@Override
	protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object mappedValue) throws Exception {
		Subject subject = getSubject(req, resp);
		String[] allArray = (String[]) mappedValue;
		if (allArray == null || allArray.length == 0) { // 没有角色限制,有权限访问
			log.info("all过滤条件为空,直接不进行权限控制");
			return true;
		}
		if (allArray.length != 1) {
			log.info("all过滤条件要求数组只有一个表达式,目前不唯一,所以不过滤");
			return true;
		}
		Map<String, Boolean> hasRoleOrPerm = new HashMap<String, Boolean>();
		String expnew = "";
		for (String exp : allArray) {
			expnew = exp;
			String[] arr = exp.split("\\s+");
			for (String ss : arr) {
				// 获取里边的role-和perm-相关的
				if (ss.indexOf("role-") != -1) {
					hasRoleOrPerm.put(ss, subject.hasRole(ss.replaceAll("role-", "")));
				}
				// 获取里边的role-和perm-相关的
				if (ss.indexOf("perm-") != -1) {
					hasRoleOrPerm.put(ss, subject.isPermitted(ss.replaceAll("perm-", "")));
				}
			}
			Set<Entry<String, Boolean>> entryset = hasRoleOrPerm.entrySet();
			for (Entry<String, Boolean> entry : entryset) {
				expnew = expnew.replace(entry.getKey(), entry.getValue().toString());
			}
			expnew = expnew.replace("and", "&&");
			expnew = expnew.replace("or", "||");
		}
		ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("js");
        Object result = engine.eval(expnew);
        return (Boolean) result;
        //System.out.println("结果类型:" + result.getClass().getName() + ",计算结果:" + result);
		//return false;
	}
}

能不能访问就是看返回的true或false。代码中先判断角色和权限判断是否有,将有改为true没有改为false,公式转化为 (true && true) || false 这种形式,这种判断虽然一眼能看出结果,但是却是字符串。所以我百度到一种方法

ScriptEngine engine = manager.getEngineByName("js");
        Object result = engine.eval(expnew);
        return (Boolean) result;

这个能把我这种字符串判断真假。

到此为止,复杂形式的权限角色资源权限判断完毕。

注意,我的公式是我自己编辑的格式,都有空格,便于截取字符串,前缀perm-用来区分在权限中找还是在role-在角色中找。添加形式和解析都是大家自由发挥的地方。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
web.xml配置 因为我们是与spring进行集成的,而spring的基本就是web项目的xml文件。所以我们在web.xml中配置shiros的过滤拦截。正常情况下,我们需要将shiro的filter配置在所有的filter前面,当然和encodingFilter这个filter是不区分前后的。因为两者互相不影响的。spring-shiro.xml 这里我们将来看看spring-shiro.xml的配置,这里我采取倒叙的方式讲解,我觉的倒叙更加的有助于我们理解代码。首先我们还记得在web.xml中配置的那个filter吧,名字shiroFilter,对spring-shiro.xml配置文件就是通过这个filter展开的。首先我们在web.xml配置的过滤器实际上是配置ShiroFilterFactoryBean,所以在这里需要将ShiroFilterFactoryBean定义为shiroFilter <!-- Shiro的核心安全接口,这个属性是必须的 --> <!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.html"页面 --> <!-- 登录成功后要跳转的连接 --> <!-- 用户访问未对其授权的资源时,所显示的连接 --> <!-- 若想更明显的测试此属性可以修改它的值,如unauthor.jsp,然后用[玄玉]登录后访问/admin/listUser.jsp就看见浏览器会显示unauthor.jsp --> <!-- Shiro连接约束配置,即过滤链的定义 --> <!-- 此处可配合我的这篇文章来理解各个过滤连的作用http://blog.csdn.net/jadyer/article/details/12172839 --> <!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的 --> <!-- anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 --> <!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter --> /statics/**=anon /login.html=anon /sys/schedule.html=perms[sys:schedule:save] /sys/login=anon /captcha.jpg=anon /**=authc

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值