Shiro教程(十)Shiro 权限动态加载与配置精细讲解

本文转载来源:Shiro教程(十)Shiro 权限动态加载与配置精细讲解

Shiro  是一个很完美的权限控制框架,一般我们会采用 shiro  的标签,在页面判断,从而来判断一些ButtonLink Tag  的显示与否,但是仅仅这样判断是不够的,如果用户知道链接,这就一点用都没有。所以我们后台还要有一层判断。这样才安全。今天来说说 Shiro  后台判断的这点事。

shiro标签讲解:

Freemarker  使用Shiro 标签的介绍:http://www.sojson.com/blog/143.html

JSP  使用Shiro 标签的介绍:http://www.sojson.com/blog/144.html

shiro一般是这样配置。

    <property name="filterChainDefinitions" >
    	<value>
    		/** = anon
    		/page/login.jsp = anon
    		/page/register/* = anon
    		/page/index.jsp = authc
    		/page/addItem* = authc,roles[数据管理员]
    		/page/file* = authc,roleOR[普通用户,数据管理员]
    		/page/listItems* = authc,roleOR[数据管理员,普通用户]
    		/page/showItem* = authc,roleOR[数据管理员,普通用户]
    		/page/updateItem*=authc,roles[数据管理员]
        </value>
    </property>

这样配置有什么问题?

shiro  加载配置,或者说校验配置,是从上而下的,也就是向上面的配置,其实是有问题的。可能不仔细看你没看出来,/** = anon  ,如果把这个配置在第一行,其实下面的配置都没用。因为是从上往下去匹配,只要匹配中了,就不匹配了,这个是重点,所以要有序

其次,我们知道,这样配置有一个问题,就是维护起来费劲,它不如单独的配置文件,比如我们常用properties 配置文件来配置一些经常修改的值。如:jdbc.properties 会配置一些数据库的链接,帐号、密码等。

说到这里,有的同学就会想,那么我们就用 properties

properties 我们来看看有什么问题?

properties 配置,其实是没问题,问题就出在读取 properties 配置上。我们一般读取,或者说常用读取properties 配置文件,都是用相对应的 Java   JDK   自带提供java.util.Properties 工具类,我们可以看到这个工具类的情况。

    public class Properties extends Hashtable<Object,Object> {
    	//Do some thing
    }


它继承了 Hashtable ,这就是出现了一个问题,Hashtable 是无序的。这就是关键点。

Shiro 权限拦截动态配置方案

1.重写java.util.Properties  工具类 ,继承 LinkedHashMap<K, V>()  ,LinkedHashMap()  是有序的。

2.自己写一个读取文件的工具类也可以解决。

我的实现是用ini配置文件,自己写了一个读取的工具类,已经封装好,欲知详情或者下载请点击:http://www.sojson.com/blog/139.html

里面有工具类的下载,本站的实现,以及本站发布的开源Demo项目:SpringMVC + Mybatis + Shiro + Redis

这个 Demo  里的配置文件:

    [base_auth]
    /u/**=anon
    /user/**=simple,login
    /js/**=anon
    /css/**=anon 
    /open/**=anon

    #不用校验地址是否有权限
    /permission/selectPermissionById.shtml=simple,login
    /member/onlineDetails/**=simple,login
    /role/mypermission.shtml=simple,login
    /role/getPermissionTree.shtml=simple,login
    /role/selectRoleByUserId.shtml=simple,login


    #需要根据地址校验有无权限
    /permission/**=simple,login,permission
    /role/**=simple,login,permission
    /member/**=simple,login,permission




    /**=simple,login


配置文件加载类:

    package com.sojson.core.shiro.service.impl;

    import java.io.IOException;
    import java.util.Map;
    import java.util.Set;

    import javax.annotation.Resource;

    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
    import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
    import org.apache.shiro.web.servlet.AbstractShiroFilter;
    import org.springframework.core.io.ClassPathResource;

    import com.sojson.common.utils.LoggerUtils;
    import com.sojson.core.config.INI4j;
    import com.sojson.core.shiro.service.ShiroManager;
    /**
     * 
     * 开发公司:SOJSON在线工具 <p>
     * 版权所有:© www.sojson.com<p>
     * 博客地址:http://www.sojson.com/blog/  <p>
     * <p>
     * 
     * 动态加载权限 Service
     * 
     * <p>
     * 
     * 区分 责任人 日期    说明<br/>
     * 创建 周柏成 2016年6月2日  <br/>
     *
     * @author zhou-baicheng
     * @email  so@sojson.com
     * @version 1.0,2016年6月2日 <br/>
     * 
     */
    public class ShiroManagerImpl implements ShiroManager {
    	
    	// 注意/r/n前不能有空格
    	private static final String CRLF = "\r\n";

    	@Resource
    	private ShiroFilterFactoryBean shiroFilterFactoryBean;


    	@Override
    	public String loadFilterChainDefinitions() {
    		
    		StringBuffer sb = new StringBuffer();
    			sb.append(getFixedAuthRule());//固定权限,采用读取配置文件
    		return sb.toString();
    	}
    	
    	/**
    	 * 从配额文件获取固定权限验证规则串
    	 */
    	private String getFixedAuthRule(){
    		String fileName = "shiro_base_auth.ini";
    		ClassPathResource cp = new ClassPathResource(fileName);
    		INI4j ini = null;
    		try {
    			ini = new INI4j(cp.getFile());
    		} catch (IOException e) {
    			LoggerUtils.fmtError(getClass(), e, "加载文件出错。file:[%s]", fileName);
    		}
    		String section = "base_auth";
    		Set<String> keys = ini.get(section).keySet();
    		StringBuffer sb = new StringBuffer();
    		for (String key : keys) {
    			String value = ini.get(section, key);
    			sb.append(key).append(" = ")
    			.append(value).append(CRLF);
    		}
    		
    		return sb.toString();

    	}

    	// 此方法加同步锁
    	@Override
    	public synchronized void reCreateFilterChains() {
    //		ShiroFilterFactoryBean shiroFilterFactoryBean = (ShiroFilterFactoryBean) SpringContextUtil.getBean("shiroFilterFactoryBean");
    		AbstractShiroFilter shiroFilter = null;
    		try {
    			shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
    		} catch (Exception e) {
    			LoggerUtils.error(getClass(),"getShiroFilter from shiroFilterFactoryBean error!", e);
    			throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
    		}

    		PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
    				.getFilterChainResolver();
    		DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver
    				.getFilterChainManager();

    		// 清空老的权限控制
    		manager.getFilterChains().clear();

    		shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
    		shiroFilterFactoryBean.setFilterChainDefinitions(loadFilterChainDefinitions());
    		// 重新构建生成
    		Map<String, String> chains = shiroFilterFactoryBean
    				.getFilterChainDefinitionMap();
    		for (Map.Entry<String, String> entry : chains.entrySet()) {
    			String url = entry.getKey();
    			String chainDefinition = entry.getValue().trim().replace(" ", "");
    			manager.createChain(url, chainDefinition);
    		}

    	}
    	public void setShiroFilterFactoryBean(
    			ShiroFilterFactoryBean shiroFilterFactoryBean) {
    		this.shiroFilterFactoryBean = shiroFilterFactoryBean;
    	}

    }


具体请查看:

本站发布的开源Demo项目:SpringMVC + Mybatis + Shiro + Redis

Github下载:https://github.com/baichengzhou/SpringMVC-Mybatis-shiro


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
12-12 605

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值