安全/权限框架Shiro(4)之过滤配置

安全/权限框架Shiro(4)之过滤配置

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

规则

这里说的过滤配置指的是在 Spring 配置中的 org.apache.shiro.spring.web.ShiroFilterFactoryBeanfilterChainDefinitions 属性的配置。具有如下规则:

匹配格式

  • 格式: url=拦截器名称[参数]
  • 如果当前请求路径匹配了某个 url,那么将会执行其对应的拦截器。
  • anon (anonymous):该拦截器表示可匿名访问,即不需要登录即可访问。
  • authc (authentication):该拦截器表示需要身份认证通过后才能访问。

匹配模式

这里的 url 使用的是 Ant 风格路径。

Ant 路径通配符支持 '?'、'*'、'**',注意通配符匹配不包括目录分隔符 '/':

  • ?:匹配一个字符,如 /admin? 将匹配 /admin1,但不匹配 /admin/admin/
  • *:匹配零个或多个字符串,如 /admin* 将匹配 /admin/admin123 ,但不匹配 /admin/1
  • **:匹配路径中零个或多个路径,如 /admin/** 将匹配 /admin/a/admin/a/b

匹配顺序

url 采取第一次匹配优先的方式,即从头开始使用第一个匹配的 url 模式对应的拦截器链。

如:

<!--如果请求的 url 是 "/bb/aa",因为按照声明顺序进行匹配,那么将使用 filter1 进行拦截。-->
<property name="filterChainDefinitions">
    <value>
        /bb/**=filter1
        /bb/aa=filter2
        /**=filter3
    </value>
</property>

动态权限

上述这种配置方式其实有一个很明显的弊端,当我们有很多过滤规则都放在配置文件中显然不合适,常常我们所需要的方式是能将权限数据保存在数据库,这样我们就可以通过操作数据库的权限数据动态的更改权限配置。那这种方式我们该如何实现呢?

因为上述配置方式实际上是将一个字符串通过 org.apache.shiro.spring.web.ShiroFilterFactoryBean#setFilterChainDefinitions 方法注入,查看这个方法:

// org.apache.shiro.spring.web.ShiroFilterFactoryBean#setFilterChainDefinitions
public void setFilterChainDefinitions(String definitions) {
    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);
}

可以看到,该方法将我们传入的过滤配置字符串进行了解析并且包装为 org.apache.shiro.config.Ini.Section 对象(继承了 java.util.Map<String,Stirng> )最终调用了 setFilterChainDefinitionMap(section)

// org.apache.shiro.spring.web.ShiroFilterFactoryBean#setFilterChainDefinitionMap
public void setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap) {
    this.filterChainDefinitionMap = filterChainDefinitionMap;
}

很明显,上述就是将我们配置的过滤字符串转换为一个 Map 对象最终赋值给 org.apache.shiro.spring.web.ShiroFilterFactoryBean#filterChainDefinitionMap 属性,所以我们只要动态的构建一个 Map 对象赋值给这个属性就实现了权限的动态过滤配置。这里要注意的我们的过滤规则是有顺序的,所以我们可以构建一个 java.util.LinkedHashMap 对象,实现如下:

1、构建 Map 工厂类:

// com.zze.shiro.utils.FilterChainDefinitionMapBuilder
import java.util.LinkedHashMap;

public class FilterChainDefinitionMapBuilder {

    public LinkedHashMap<String, String> buildFilterChainDefinitionMap() {
        LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
        // 数据可以从数据库中获取
        map.put("/bb/**", "filter1");
        map.put("/bb/aa", "filter2");
        map.put("/**", "filter3");
        return map;
    }
}

2、通过 Spring 的工厂方式注入 filterChainDefinitionMap 属性:

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <property name="loginUrl" value="/login.jsp"/>
    <property name="successUrl" value="/list.jsp"/>
    <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
    <property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"/>
</bean>

<bean id="filterChainDefinitionMapBuilder" class="com.zze.shiro.handlers.FilterChainDefinitionMapBuilder"/>

<bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapBuilder" factory-method="buildFilterChainDefinitionMap"/>

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/shiro4.html

Buy me a cup of coffee ☕.