shiro 的全新控制怎么动态

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shiro 的全新控制怎么动态相关的知识,希望对你有一定的参考价值。

html] view plain copy
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

@Autowired
private SimpleCacheManager simpleCacheManager;

@Autowired
private PermissionService permissionService;

@Override
public 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作为展现层,具体怎么配置整合我也不说,百度一堆,直接看我帖代码说明

[html] view plain copy
<!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的实现

[html] view plain copy
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

@Autowired
private 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配置

[html] view plain copy
<!-- 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的人都能看明白,我也不累赘说明;最后再说一句,谢谢大家支持.
参考技术A

‍推荐一套完整的Shiro Demo,免费的。

Shiro介绍文档:http://www.sojson.com/shiro
Demo已经部署到线上,ShiroDemo:http://shiro.itboy.net

管理员帐号:admin,密码:sojson.com 如果密码错误,请用sojson。PS:你可以注册自己的帐号,然后用管理员赋权限给你自己的帐号,但是,每20分钟会把数据初始化一次。建议自己下载源码,让Demo跑起来,然后跑的更快。

本回答被提问者采纳

shiro动态控制url资源

怎么利用shiro权限动态控制每个url资源呢?主要包括jsp(html)页面、action的url访问,而静态资源和登录资源则可直接访问。

所谓动态控制url就是url的权限控制不是手动写死在配置文件中,而是根据数据库的变化而变化。

表结构:

user2:用户表

t_role:角色表

t_user_role:用户角色表

t_privilege:权限资源表

t_role_privilege:角色权限资源表

shiro动态控制url资源:

applicationContext-shiro.xml配置chainDefinitionSectionMetaSource:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <description>apache shiro配置</description>
    
    <bean id="chainDefinitionSectionMetaSource" class="com.test.www.web.filter.ChainDefinitionSectionMetaSource">
        <property name="filterChainDefinitions">
               <value>
                   <!-- 静态资源允许访问 -->
                <!-- /** = anon -->
                <!-- /app/** = anon
                /assets/** = anon -->
                <!-- 登录页允许访问 -->
                   <!--  /user/login.htm = anon -->
                <!-- /login.jsp = anon  -->
                <!-- /*.jsp = anon -->
                <!-- /js/**=anon -->
                <!-- 登录页面 -->
                /index2.jsp = anon
                /js/** = anon
                /css/** = anon
                /images/** = anon
                /assets/** = anon
                /test/loginAdmin.html=anon
                /logout=logout  <!-- 这才是对退出的配置 --> 
                <!-- /test/add.html = perms["user:add"] -->      
                <!-- /test/add.html = perms["/test/add.html"] -->
                <!-- 其他资源需要认证 -->
                <!-- /** = authc -->
                <!-- /logout=logout -->  <!-- 这才是对退出的配置,不能放在/** = authc的后面 --> 
                
            </value>
        </property>
    </bean>
    
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="filters">
            <map>
                <entry key="logout" value-ref="logoutFilter"/>
            </map>
        </property>
        <property name="securityManager" ref="securityManager"/>
       <!--  <property name="loginUrl" value="/index2.jsp"/>
        <property name="successUrl" value="/main/main.htm"/>
        <property name="unauthorizedUrl" value="/page/401.htm"/> -->
        <!-- shiro判断是否登录,没有登录则跳转到登录页面,loginUrl对应登录页面的路径 -->
        <property name="loginUrl" value="/index2.jsp"/>
        <property name="unauthorizedUrl" value="/page/401.htm"/><!-- /page/401.htm -->
        
        <property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" />
    </bean>

    <!-- 缓存管理器 使用Ehcache实现 -->
    <!-- 
    <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager" p:cacheManagerConfigFile="/WEB-INF/conf/ehcache-shiro.xml">
    </bean>
     -->
    <!-- 会话DAO -->
    <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.MemorySessionDAO"/>

    <!-- 会话管理器 -->
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <property name="sessionDAO" ref="sessionDAO"/>
    </bean>

    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realms">
            <list>
                <ref bean="securityRealm"/>
            </list>
        </property>
        <!-- cacheManager,集合spring缓存工厂 -->
        <!-- <property name="cacheManager" ref="shiroEhcacheManager" />
        <property name="sessionManager" ref="sessionManager" /> -->
    </bean>

    <!-- Shiro生命周期处理器 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

</beans>

ChainDefinitionSectionMetaSource.java:

package com.test.www.web.filter;

import java.text.MessageFormat;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.config.Ini;
import org.apache.shiro.config.Ini.Section;
import org.springframework.beans.factory.FactoryBean;

import com.test.www.web.entity.user.TPrivilege;
import com.test.www.web.service.user.TPrivilegeService;

public class ChainDefinitionSectionMetaSource implements FactoryBean<Ini.Section>{

public static final String PREMISSION_STRING="perms[\\"{0}\\"]";
    
    private String filterChainDefinitions;
    
    /*private PrivilegeDao privilegeDao;

    public PrivilegeDao getPrivilegeDao() {
        return privilegeDao;
    }*/
    
    @Resource
    private TPrivilegeService tPrivilegeService;
    
    public String getFilterChainDefinitions() {
        return filterChainDefinitions;
    }
    
    @Resource
    public void setFilterChainDefinitions(String filterChainDefinitions) {
        String fiter="";//改正后的url配置
        /*List<Privilege> list = privilegeDao.getAll();
        for (Iterator<Privilege> it = list.iterator(); it.hasNext();) {
            Privilege privilege = it.next();
            if(!StringUtils.isEmpty(privilege.getUrl())) {
                fiter+="/"+privilege.getUrl()+" = authc," +MessageFormat.format(PREMISSION_STRING,privilege.getPerms()) +"\\n";
            }//追加beans.xml中已经有的过滤
        }*/
        
        List<TPrivilege> tPrivilegeList = tPrivilegeService.selectAllPrivileges();
        if(tPrivilegeList!=null && tPrivilegeList.size()>0){
            for (TPrivilege tPrivilege : tPrivilegeList) {
                if(!StringUtils.isEmpty(tPrivilege.getUrl())) {
                    fiter += tPrivilege.getUrl()+" = authc," +MessageFormat.format(PREMISSION_STRING,tPrivilege.getUrl()) +"\\n";
                }//追加beans.xml中已经有的过滤
            }
        }
        
        //对url拦截
        fiter += "/**"+" = authc" +"\\n";
        //fiter+="/test/add.html"+" = authc," +MessageFormat.format(PREMISSION_STRING,"/test/add.html") +"\\n";
        //fiter+="/js/**"+" = authc," +MessageFormat.format(PREMISSION_STRING,"/js/**") +"\\n";
        //fiter+="/js/**"+" = " +MessageFormat.format(PREMISSION_STRING,"/js/**") +"\\n";
        System.out.println(filterChainDefinitions+fiter);
        this.filterChainDefinitions = filterChainDefinitions+fiter;
    }

    /*@Resource
    public void setPrivilegeDao(PrivilegeDao privilegeDao) {
        this.privilegeDao = privilegeDao;
    }*/
    
    public Section getObject(){
        Ini ini = new Ini();//网上好多都是在这里配置URL的。但是发现是错误的。
        ini.load(filterChainDefinitions);
        Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
        return section;
    }

    public Class<?> getObjectType() {
        return this.getClass();
    }

    public boolean isSingleton() {
        return false;
    }

}

服务器启动的时候会执行ChainDefinitionSectionMetaSource类,加载系统权限资源表所有的url到filterChainDefinitions中(在filterChainDefinitions后追加),从而实现对所有url资源的权限控制的配置:

这个类就是用来在filterChainDefinitions中追加url资源权限控制的。


注意:

/** = authc应放在最后,否则会影响追加的权限资源的控制。

当访问资源的时候,例如/test/toAddUser.html,就会进入shiro授权方法中进行权限校验,如果没有权限则进入到401未授权,否则正常访问。

SecurityRealm.java:

package com.test.www.web.security;

import java.util.List;

import javax.annotation.Resource;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Component;

import com.test.www.web.entity.user.TRolePrivilegeKey;
import com.test.www.web.entity.user.TUserRoleKey;
import com.test.www.web.entity.user.User;
import com.test.www.web.service.user.TRolePrivilegeService;
import com.test.www.web.service.user.TUserRoleService;
import com.test.www.web.service.user.UserService;

/**
 * 用户身份验证,授权 Realm 组件
 * 
 **/
@Component(value = "securityRealm")
public class SecurityRealm extends AuthorizingRealm {
    @Resource
    private UserService userService;
    @Resource
    private TUserRoleService tUserRoleService;
    @Resource
    private TRolePrivilegeService tRolePrivilegeService;
    /**
     * 权限检查
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        /*SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        String username = String.valueOf(principals.getPrimaryPrincipal());

        System.out.println("ssssssss");*/
        String username = principals.getPrimaryPrincipal().toString() ;
        System.out.println(username);
        
        Subject subject = SecurityUtils.getSubject();
        User user = (User)subject.getPrincipal();
        
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo() ;
        
        /*Set<String> roleName = t_userService.findRoles(username) ;
        Set<String> permissions = t_userService.findPermissions(username) ;*/
        //final List<Role> roleInfos = roleService.selectRolesByUserId(user.getUserId());
        /*for (Role role : roleInfos) {
            // 添加角色
            System.err.println(role);
            authorizationInfo.addRole(role.getRoleSign());

            final List<Permission> permissions = permissionService.selectPermissionsByRoleId(role.getRoleId());
            for (Permission permission : permissions) {
                // 添加权限
                System.err.println(permission);
                authorizationInfo.addStringPermission(permission.getPermissionSign());
            }
        }*/
        
        List<TUserRoleKey> tUserRoleKeyList = tUserRoleService.selectRolesByUserId(user.getId());
        if(tUserRoleKeyList != null && tUserRoleKeyList.size()>0){
            for(TUserRoleKey tUserRoleKey : tUserRoleKeyList){
                authorizationInfo.addRole(tUserRoleKey.getCode());
                List<TRolePrivilegeKey> tRolePrivilegeKeyList = tRolePrivilegeService.selectPrivilegesByRoleId(tUserRoleKey.getRoleId());
                for(TRolePrivilegeKey tRolePrivilegeKey : tRolePrivilegeKeyList){
                    authorizationInfo.addStringPermission(tRolePrivilegeKey.getUrl());
                }
            }
        }
        //Set<String> roleName = new HashSet<String>();
        //Set<String> permissions = new HashSet<String>();
        //查询角色
        //roleName.add("admin");
        //根据角色查询权限
        //permissions.add("/test/add.html1"); //pub:coursecategory user:add
        //permissions.add("/js/**");
        //permissions.add("/jsp");
        //authorizationInfo.setRoles(roleName);
        //authorizationInfo.setStringPermissions(permissions);
        return authorizationInfo;
    }

    /**
     * 登录验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        /* String username = String.valueOf(token.getPrincipal());
        String password = new String((char[]) token.getCredentials());
        System.out.println("aaaaaaa");
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, password, getName());*/
        //int i = 1/0;
        
        //获取用户账号
        //验证账号密码
        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
        System.out.println("1:"+userToken.getUsername());
        User user = userService.getUserByUserName(userToken.getUsername());
        System.out.println("2");
        if (user != null){
            //将查询到的用户账号和密码存放到 authenticationInfo用于后面的权限判断。第三个参数传入realmName。
            AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(),this.getClass().getSimpleName()) ;
            return authenticationInfo ;
        }else{
            return  null ;
        }
    }

}

至此,shiro动态控制url权限资源已完成。
说明:

url资源(action、静态html或动态页面jsp的url)保存在数据库中。

 

以上是关于shiro 的全新控制怎么动态的主要内容,如果未能解决你的问题,请参考以下文章

shiro框架 RequiresPermissions注解怎么动态配置

shiro框架 RequiresPermissions注解怎么动态配置

第十九章 动态URL权限控制——《跟我学Shiro》

springboot+shiro+redis(单机redis版)整合教程-续(添加动态角色权限控制)

LayUI + Shiro 实现动态菜单并记住菜单收展

JWT的权限控制与Shiro入门