shiro安全框架扩展教程--如何动态控制页面节点元素的权限
来源:互联网 发布:苏州seo招聘 编辑:程序博客网 时间:2024/05/21 16:14
上些章节我们都学习了shiro中的各种实际应用技巧,今天我想讲的是如何动态控制页面节点权限,相信这个控制对于很多玩权限的人来说都是一个比较头痛的,
因为这实在不怎么好统一控制的,现在我来展示下我通过shiro是如何实现的,算是抛砖引玉,希望大家有更好的解决方案,可以相互学习;下面就直接进入主题不啰嗦了
之前我们已经学习了如何在项目启动的时候加载所有的资源角色,包括第三方资源,下面我再帖上加长加粗版的代码方便说明
package com.silvery.security.shiro.service.impl;import java.text.MessageFormat;import java.util.HashMap;import java.util.HashSet;import java.util.List;import java.util.Map;import java.util.Set;import org.apache.shiro.cache.Cache;import org.springframework.beans.factory.annotation.Autowired;import com.silvery.project.cms.model.Authority;import com.silvery.project.cms.model.Permission;import com.silvery.project.cms.service.PermissionService;import com.silvery.project.cms.vo.PermissionVo;import com.silvery.security.shiro.cache.SimpleMapCache;import com.silvery.security.shiro.cache.extend.SimpleCacheManager;import com.silvery.security.variable.Const;/** * * 加载第三方角色资源配置服务类 * * @author shadow * */public class SimpleFilterChainDefinitionsService extends AbstractFilterChainDefinitionsService {@Autowiredprivate SimpleCacheManager simpleCacheManager;@Autowiredprivate PermissionService permissionService;@Overridepublic Map<String, String> initOtherPermission() {return converResultMap(initOperation());}@SuppressWarnings("unchecked")private Map<Object, Object> initOperation() {Map<Object, Object> resultMap = new HashMap<Object, Object>();// 加载数据库所有资源PermissionVo vo = new PermissionVo();List<Permission> permissions = (List<Permission>) permissionService.query(vo).getValue();List<Authority> authorities = null;for (Permission permission : permissions) {// 遍历查询当前资源的配置角色vo.setId(permission.getId());authorities = (List<Authority>) permissionService.query4authority(vo).getValue();// 组装角色集合Set<String> authoritySet = getPermissionSet(authorities);if (authoritySet.isEmpty()) {continue;}if (permission.getType() == 1) {// 请求路径资源处理resultMap.put(permission.getContent(), MessageFormat.format(SHIRO_AUTHORITY_FORMAT, authoritySet));} else {// 元素资源处理Map<Object, Object> map = new HashMap<Object, Object>(1);map.put(Const.OTHER_PERMISSSION_CACHE_NAME, authoritySet);Cache<Object, Object> cache = new SimpleMapCache(Const.OTHER_PERMISSSION_CACHE_NAME, map);simpleCacheManager.createCache(Const.OTHER_PERMISSSION_CACHE_NAME + "_" + permission.getId(), cache);}}return resultMap;}/** 获取角色名称集合 */private Set<String> getPermissionSet(List<Authority> authorities) {Set<String> authoritieSet = new HashSet<String>(authorities.size());for (Authority authority : authorities) {authoritieSet.add(authority.getContent());}return authoritieSet;}/** 泛型Object转换String */private Map<String, String> converResultMap(Map<Object, Object> map) {Map<String, String> resultMap = new HashMap<String, String>(map.size());for (Map.Entry<Object, Object> entry : map.entrySet()) {resultMap.put(entry.getKey().toString(), entry.getValue().toString());}return resultMap;}}
1. 加载所有资源,包括请求URL,元素节点等数据,我这里为了演示,没有分那么细就只有两种
2. 请求URL的直接放到框架中,形式如/user/list.do*=role[root,user],跟我们shiro.xml配置的一样
3. 元素节点则相应放到以键值对的形式放到缓存,以节点的编号组合成key保证可以找到这个缓存对,值是相应的角色集合
我们的缓存就存在各个资源所需要的角色集合, 加载数据步骤已经完毕了下面看看我们是怎么应用的
首先我是使用springMVC+freemarker作为展现层,具体怎么配置整合我也不说,百度一堆,直接看我帖代码说明
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>欢迎主页</title></head><body>${username!"游客"}, 欢迎您的访问! <br /><hr />可选操作:<#if username??><@sec id="2" body="<a href='/cms/user/page.do'>用户列表</a> " /><a href="/cms/authority/page.do">权限列表</a> <a href="/cms/permission/page.do">资源列表</a> <a href="/cms/logout.do">注销退出</a> <#else><a href="#" onclick="top.location.href='/cms/logout.do';">前往登录</a> </#if><hr /></body></html>
很明显看到我的页面有一个@sec的标签,然后有两个参数,一个id,一个是body,至于id则是你资源的编号,body是需要元素节点内容
然后我们怎么通过这个标签来判定是否在页面渲染body的节点内容呢?
下面我们看看这个@sec的实现
package com.silvery.core.freemarker;import java.io.IOException;import java.util.Map;import java.util.Set;import org.apache.shiro.SecurityUtils;import org.apache.shiro.cache.Cache;import org.apache.shiro.subject.Subject;import org.springframework.beans.factory.annotation.Autowired;import com.silvery.security.shiro.cache.extend.SimpleCacheManager;import com.silvery.security.variable.Const;import freemarker.core.Environment;import freemarker.template.TemplateDirectiveBody;import freemarker.template.TemplateDirectiveModel;import freemarker.template.TemplateException;import freemarker.template.TemplateModel;/** * * FreeMarker自定义标签,节点权限控制 * * @author shadow * */public class SecurityTag implements TemplateDirectiveModel {@Autowiredprivate SimpleCacheManager simpleCacheManager;@SuppressWarnings("unchecked")public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody directiveBody)throws TemplateException, IOException {Object id = params.get("id");Object body = params.get("body");validate(id, body);if (hasRole(id)) {env.getOut().write(body.toString());} else {env.getOut().write("");}}private void validate(Object id, Object body) throws TemplateException {if (id == null || id.toString().trim().equals("")) {throw new TemplateException("参数[id]不能为空", null);}if (body == null) {throw new TemplateException("参数[body]不能为空", null);}}@SuppressWarnings("unchecked")private boolean hasRole(Object id) {Cache<Object, Object> cache = simpleCacheManager.getCache(Const.OTHER_PERMISSSION_CACHE_NAME + "_" + id);if (cache == null) {return false;} else {Object obj = cache.get(Const.OTHER_PERMISSSION_CACHE_NAME);if (obj == null) {return false;}Set<String> authoritySet = (Set<String>) obj;Subject subject = SecurityUtils.getSubject();for (String authority : authoritySet) {if (subject.hasRole(authority)) {return true;}}}return false;}}
很清晰地看到,我们是用到之前的那个资源角色缓存,通过判定缓存中存在的角色与当前shiro认证用户拥有的角色匹配,如存在任意相同角色则渲染相应节点
如Subject拥有角色[root,user],而x编号资源拥有[user,test]角色,很明显有交集会认证通过,反之则直接渲染空字符
大概流程就是这样,有的人可能会问,如何配置这个tag实现类呢?我帖下spring-mvc.xml的freemarker配置
<!-- FreeMarker配置 --><bean id="freemarkerConfig"class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"><property name="templateLoaderPath" value="/WEB-INF/ftl/" /><property name="defaultEncoding" value="UTF-8" /><property name="freemarkerVariables"><map><entry key="sec"><bean class="com.silvery.core.freemarker.SecurityTag"></bean></entry></map></property><property name="freemarkerSettings"><props><prop key="template_update_delay">10</prop><prop key="locale">zh_CN</prop><prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop><prop key="date_format">yyyy-MM-dd</prop><prop key="number_format">#.####</prop></props></property></bean>
相信懂freemarker的人都能看明白,我也不累赘说明;最后再说一句,谢谢大家支持.
0 0
- shiro安全框架扩展教程--如何动态控制页面节点元素的权限
- shiro安全框架扩展教程--如何动态控制页面节点元素的权限
- shiro安全框架扩展教程--如何动态修改资源权限不需要重启项目
- shiro安全框架扩展教程--上传文件的安全控制
- shiro安全框架扩展教程--如何自定义适合项目的过滤器
- shiro安全框架扩展教程--如何防止可执行文件的入侵攻击
- shiro安全框架扩展教程--如何扩展实现我们的缓存机制(第三方容器redis,memcached)
- shiro安全框架扩展教程--如何扩展实现我们的缓存机制(第三方容器redis,memcached)
- shiro安全框架扩展教程--如何扩展实现我们的缓存机制(第三方容器redis,memcached)
- shiro安全框架扩展教程--如何扩展异步(ajax)请求认证失败处理
- shiro安全框架扩展教程--如何扩展实现集中式session管理
- shiro安全框架扩展教程--如何扩展实现集中式session管理(redis,memcached等)
- shiro安全框架扩展教程--如何扩展异步(ajax)请求认证失败处理
- shiro安全框架扩展教程--验证码的安全(jcaptcha框架)
- shiro安全框架扩展教程--设计数据对象校验器,如何防止xss以及csrf攻击
- 利用shiro实现权限的动态控制
- [笔记-架构探险]框架优化与功能扩展3.2.安全框架shiro、提供安全控制特性2-jsp页面标签和框架aop启用权限控制
- shiro安全框架扩展教程--如何扩展realm桥接器并退出自动清空角色资源缓存
- 1的数目(编程之美 java版)
- VC 未定义的标识符
- 枚举类
- hdu1754——I Hate It
- 自定义View常处理的回调函数
- shiro安全框架扩展教程--如何动态控制页面节点元素的权限
- C/C++语言学习后的不明之处1
- C++和Objective-C混编
- Access 关键字引发的调试错误
- 让vim编辑时不生成副本文件
- gdb基本用法
- 任务调度 (好资料)
- Collection集合
- SimpleDateFormat、DecimalFormat