• 续上篇---shiro从数据库获取动态权限-cjq


    个人觉得,上篇中讲到的注解的方式来控制方法的访问权限并没有那么灵活,且需要在代码中硬编码,复用性不高,移植会很麻烦,故研究了下从数据库中动态加载权限

    即shiro.xml中的ShiroFilterFactoryBean,之前是直接加载apache源码的bean:<bean id="shiroFilter" class="cn.cjq.util.shiro.ShiroPermissionFactory">

    现在做出以下自定义shiro的filter   该bean继承ShiroPermissionFactory,重写父类的setFilterChainDefinitions(java.lang.String definitions)方法

    首先来看ShiroPermissionFactory源码,配置文件中的property 都是在为ShiroPermissionFactory属性赋值

    源码部分:

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


    // IntelliJ API Decompiler stub source generated from a class file
    // Implementation of methods is not available

    package org.apache.shiro.spring.web;

    public class ShiroFilterFactoryBean implements org.springframework.beans.factory.FactoryBean, org.springframework.beans.factory.config.BeanPostProcessor {
    private static final transient org.slf4j.Logger log;
    private org.apache.shiro.mgt.SecurityManager securityManager;
    private java.util.Map<java.lang.String,javax.servlet.Filter> filters;
    private java.util.Map<java.lang.String,java.lang.String> filterChainDefinitionMap;
    private java.lang.String loginUrl;
    private java.lang.String successUrl;
    private java.lang.String unauthorizedUrl;
    private org.apache.shiro.web.servlet.AbstractShiroFilter instance;

    public ShiroFilterFactoryBean() { /* compiled code */ }

    public org.apache.shiro.mgt.SecurityManager getSecurityManager() { /* compiled code */ }

    public void setSecurityManager(org.apache.shiro.mgt.SecurityManager securityManager) { /* compiled code */ }

    public java.lang.String getLoginUrl() { /* compiled code */ }

    public void setLoginUrl(java.lang.String loginUrl) { /* compiled code */ }

    public java.lang.String getSuccessUrl() { /* compiled code */ }

    public void setSuccessUrl(java.lang.String successUrl) { /* compiled code */ }

    public java.lang.String getUnauthorizedUrl() { /* compiled code */ }

    public void setUnauthorizedUrl(java.lang.String unauthorizedUrl) { /* compiled code */ }

    public java.util.Map<java.lang.String,javax.servlet.Filter> getFilters() { /* compiled code */ }

    public void setFilters(java.util.Map<java.lang.String,javax.servlet.Filter> filters) { /* compiled code */ }

    public java.util.Map<java.lang.String,java.lang.String> getFilterChainDefinitionMap() { /* compiled code */ }

    public void setFilterChainDefinitionMap(java.util.Map<java.lang.String,java.lang.String> filterChainDefinitionMap) { /* compiled code */ }

    public void setFilterChainDefinitions(java.lang.String definitions) { /* compiled code */ }

    public java.lang.Object getObject() throws java.lang.Exception { /* compiled code */ }

    public java.lang.Class getObjectType() { /* compiled code */ }

    public boolean isSingleton() { /* compiled code */ }

    protected org.apache.shiro.web.filter.mgt.FilterChainManager createFilterChainManager() { /* compiled code */ }

    protected org.apache.shiro.web.servlet.AbstractShiroFilter createInstance() throws java.lang.Exception { /* compiled code */ }

    private void applyLoginUrlIfNecessary(javax.servlet.Filter filter) { /* compiled code */ }

    private void applySuccessUrlIfNecessary(javax.servlet.Filter filter) { /* compiled code */ }

    private void applyUnauthorizedUrlIfNecessary(javax.servlet.Filter filter) { /* compiled code */ }

    private void applyGlobalPropertiesIfNecessary(javax.servlet.Filter filter) { /* compiled code */ }

    public java.lang.Object postProcessBeforeInitialization(java.lang.Object bean, java.lang.String beanName) throws org.springframework.beans.BeansException { /* compiled code */ }

    public java.lang.Object postProcessAfterInitialization(java.lang.Object bean, java.lang.String beanName) throws org.springframework.beans.BeansException { /* compiled code */ }

    private static final class SpringShiroFilter extends org.apache.shiro.web.servlet.AbstractShiroFilter {
    protected SpringShiroFilter(org.apache.shiro.web.mgt.WebSecurityManager webSecurityManager, org.apache.shiro.web.filter.mgt.FilterChainResolver resolver) { /* compiled code */ }
    }
    }------------------------------------------------------------------------------------------------------------------------------------------------
    shiro.xml配置部分内容
    <!-- 自定义shiro的filter -->

    <bean id="shiroFilter" class="cn.cjq.util.shiro.ShiroPermissionFactory">
    <property name="securityManager" ref="securityManager"/>
    <property name="loginUrl" value="/login/toLogin.do"/>
    <property name="unauthorizedUrl" value="/login/403.do"/>
    <property name="filters">
    <map>
    <entry key="authc" value-ref="formAuthenticationFilter"/>
    </map>
    </property>
    <property name="filterChainDefinitions"> //该部分的值被重写,部分数据从数据库加载
    <value>
    /login/**=anon
    /api/** = authc
    /main.do = authc
    </value>
    </property>
    </bean>
    ------------------------------------------------------------------------------------------------------------------------------------
    自定义的shiro拦截器ShiroPermissionFactory
    package cn.cjq.util.shiro;
    import cn.cjq.entity.Menu;
    import cn.cjq.service.user.UserService;
    import org.apache.shiro.config.Ini;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.util.CollectionUtils;
    import org.apache.shiro.web.config.IniFilterChainResolverFactory;
    import javax.annotation.Resource;
    import java.util.List;

    public class ShiroPermissionFactory extends ShiroFilterFactoryBean {

    /**配置中的过滤链*/
    public static String definitions;

    /**权限service*/
    @Resource
    private UserService userServiceImpl;

    /**
    * 从数据库动态读取权限
    */
    @Override
    public void setFilterChainDefinitions(String definitions) {
    ShiroPermissionFactory.definitions = definitions;

    //数据库动态权限
    List<Menu> Menulist= null;
    try {
    Menulist = userServiceImpl.ListMenu();
    } catch (Exception e) {
    e.printStackTrace();
    }
    //拼接所有请求(即url)所需要的权限(认证,权限ID),拼接时必须加入 用来换行,否则无效
    for(Menu menu : Menulist){
    //字符串拼接权限
    definitions = definitions+menu.getUrl() + " = "+"authc,perms["+menu.getMenuid()+"] ";
    }

    //从配置文件加载权限配置
    Ini ini = new Ini();
    ini.load(definitions);
    Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
    if (CollectionUtils.isEmpty(section)) {
    section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
    }

    //加入权限集合
    setFilterChainDefinitionMap(section);
    }

    /**
    * 从数据库动态加载权限
    */
    // public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
    // ShiroFilterFactoryBean shiroFilterFactoryBean=null;
    // try {
    // shiroFilterFactoryBean = new MyShiroFilterFactoryBean();
    // //下列属性在配置文件中已配置
    //// shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());
    //// shiroFilterFactoryBean.setLoginUrl("/login");
    //// shiroFilterFactoryBean.setSuccessUrl("/index.html");
    //// shiroFilterFactoryBean.setUnauthorizedUrl("/403");
    // loadShiroFilterChain(shiroFilterFactoryBean);
    // } catch (Exception e) {
    // e.printStackTrace();
    // }
    // return shiroFilterFactoryBean;
    // }
    //
    // private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean) throws Exception {
    // List<Menu> Menulist = userServiceImpl.ListMenu();
    // Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
    // for (Menu menu : Menulist) {
    // filterChainDefinitionMap.put(menu.getUrl(),"authc,perms["+menu.getMenuid()+"]");
    // }
    // //配置文件中已配置
    //// filterChainDefinitionMap.put("/login", "anon");
    // shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    // }
    }
    -------------------------------------------------------------------------------------------------------------------------------
    上述列出的是所有url所需的相对应权限ID,下面是自定义realm中的授权信息,列出当前用户所有的权限ID,通过比较是否存在权限问题。(也可通过角色去比较,暂不做说明)
    /**
    * 授权信息
    */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    String username = (String)principals.getPrimaryPrincipal();
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    // UserService userService = (UserService) SpringContextUtil.getBean("userServiceImpl");
    try {
    authorizationInfo.setRoles(userMapper.findUserRoles(username));
    authorizationInfo.setStringPermissions(userMapper.findUserPermissions(username));
    } catch (Exception e) {

    e.printStackTrace();
    }
    return authorizationInfo;
    }
    ------------------------------------------------------------------------------------------------------------------------------------------
    根据当前用户获取所有权限ID:也可以不根据权限ID,使用别的也可,但必须统一,既然是使用了权限ID,所有查询结果返回权限ID即可
    <!-- 根据用户名查询获取权限列表ID -->
    <select id="findUserPermissions" resultType="java.lang.String" parameterType="java.lang.String" >
    SELECT
    m.menuId
    FROM mif_user u
    LEFT JOIN mif_role_user_ref ur ON u.uerId=ur.userId
    LEFT JOIN mif_role r ON r.roleId=ur.roleId
    LEFT JOIN mif_role_authority_ref ar ON ar.roleId=r.roleId
    LEFT JOIN mif_authority a ON a.authorityId=ar.authorityId
    LEFT JOIN mif_authotity_menu_ref mr ON mr.authorityId=ar.authorityId
    LEFT JOIN mif_menu m ON m.menuId=mr.menuId
    WHERE u.isdelete = 0 AND r.isdelete=0 AND a.isdelete=0 AND m.isdelete=0 AND u.userName = #{0}
    </select>
    --------------------------------------------------------------------------------------------------------------------------------------------
    坑1:上述标红的 未使用,无效果
    坑2:在初始化静态拦截的时候存在初始值/person/**= authc,即/person下的所有方法只要通过认证即可请求。但是shiro权限中数据库的动态数据也包含了/person下的方法,是无效的,原因
    是自定义的shiro的filter先加载配置文件中的数据,再加载数据库动态数据,存在/person/**= authc在前面时会让部分数据库/person下的url失效,注释掉/person/**= authc即可
     <property name="filterChainDefinitions">     //该部分的值被重写,部分数据从数据库加载
    <value>
    /login/**=anon
    /api/** = authc
    /main.do = authc
    /person/**= authc
    </value>
    </property>
    坑3:该bean只会在系统启动时加载一次,之后不会调用,所有存在任何权限上的变动时,需手动调用setFilterChainDefinitions()方法
    PS:要记住在增删改权限数据库时记得调用setFilterChainDefinitions()方法重新加载
    相关url:http://blog.csdn.net/u010351766/article/details/70432227
    
    
  • 相关阅读:
    Web API总结
    @Html.Raw() 方法输出带有html标签的字符串
    jQuery
    图与树基础-完全图的判定
    图和树基础-蒜头君旅行
    PAT乙级1008
    PAT乙级1007
    PAT乙级1005
    PAT乙级1001
    前端工程化-webpack简介(一)
  • 原文地址:https://www.cnblogs.com/1234cjq/p/8080156.html
Copyright © 2020-2023  润新知