shiro动态配置过滤器

在创建AbstractShiroFilter(shiro过滤器)时,可以配置过滤器,比如:

@Bean("shiroFilter")
    @DependsOn({"securityManager"})
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilter  = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        // 拦截器,放在其他地方任意配置
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 验证码允许匿名访问
        filterChainDefinitionMap.put("/**/test1", "anon");
        filterChainDefinitionMap.put("/**", "anon");
        filterChainDefinitionMap.put("/**/test2/**", "roles[admin,user]");
        filterChainDefinitionMap.put("/**/test2/**", "perms[admin,user],roles[admin,user]");

        shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);

        //自定义filter
        Map<String, Filter> filters = new LinkedHashMap<>();
        filters.put("loginFilter", new LoginFilter());
        shiroFilter.setFilters(filters);

        //未授权界面;
        //shiroFilter.setUnauthorizedUrl("/unauthorized");

        return shiroFilter;
    }

但有时需要在AbstractShiroFilter创建之后,任意时刻配值。因为权限过滤器中的权限是在数据库中配置的,在修改数据库中的配置时,也要动态修改内存中的过滤器配置。

在ShiroFilterFactoryBean创建AbstractShiroFilter进入该方法:

org.apache.shiro.spring.web.ShiroFilterFactoryBean#getObject  ====>org.apache.shiro.spring.web.ShiroFilterFactoryBean#createInstance====>org.apache.shiro.spring.web.ShiroFilterFactoryBean#createFilterChainManager

可见该方法拿到了配置的过滤器map,最后还设置了默认路径的过滤器。

 

在shiro最主要的类过滤器管理器DefaultFilterChainManager中

可见filters是过滤器名和过滤器的映射,filterChains是路径和过滤器名的映射。配置过滤器主要就是这2个map

 

回到org.apache.shiro.spring.web.ShiroFilterFactoryBean#createInstance

可见DefaultFilterChainManager存在了PathMatchingFilterChainResolver中,PathMatchingFilterChainResolver又存在了SpringShiroFilter中,

所以拿到DefaultFilterChainManager在修改里面的filterChains就能随时修改资源和过滤器的映射,注意还要设置默认路径/**。

 

结合https://blog.csdn.net/yaoct/article/details/115947781第4节,特别注意org.apache.shiro.web.filter.mgt.DefaultFilterChainManager#applyChainConfig中会在每个过滤器中添加路径,所以每次更新,清空过滤器的配置路径,否则会产生冗余数据

appliedPaths默认不可访问,所以通过反射修改。

参考org.apache.shiro.spring.web.ShiroFilterFactoryBean#createFilterChainManager中的代码,重置访问映射

package com.zjzy.runner;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zjzy.dao.servicebase.SysPermissionServiceBase;
import com.zjzy.dao.servicebase.SysResourcePermissionServiceBase;
import com.zjzy.model.po.SysDept;
import com.zjzy.model.po.SysLog;
import com.zjzy.model.po.SysPermission;
import com.zjzy.model.po.SysResourcePermission;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.filter.PathMatchingFilter;
import org.apache.shiro.web.filter.mgt.*;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import java.lang.reflect.Field;
import java.util.*;

@Slf4j
@Component
public class ShiroRunner implements ApplicationRunner {
    
    @Autowired
    SysResourcePermissionServiceBase sysResourcePermissionServiceBase;

    @Autowired
    SysPermissionServiceBase sysPermissionServiceBase;

    @Autowired
    ShiroFilterFactoryBean shiroFilterFactoryBean;

    @Autowired
    @Qualifier("shiroFilter")
    AbstractShiroFilter abstractShiroFilter;
    
    @Override
    public void run(ApplicationArguments args) throws Exception {

        PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver)abstractShiroFilter.getFilterChainResolver();
        DefaultFilterChainManager manager = (DefaultFilterChainManager)filterChainResolver.getFilterChainManager();
        Map<String, Filter> filters = manager.getFilters();
        //清空appliedPaths
        for(Filter filter:filters.values()){
            if(filter instanceof PathMatchingFilter){
                Class<PathMatchingFilter> pathMatchingFilterClass = PathMatchingFilter.class;
                Class<? extends Filter> aClass = filter.getClass();
                Field[] declaredFields = aClass.getDeclaredFields();
                Field appliedPaths=null;
                try{
                    appliedPaths=PathMatchingFilter.class.getDeclaredField("appliedPaths");
                }catch (Exception e){
                    continue;
                }
                if(appliedPaths!=null){
                    appliedPaths.setAccessible(true);
                    if(appliedPaths.getType().isAssignableFrom(Map.class)){
                        appliedPaths.set(filter,new LinkedHashMap<String,Object>());
                    }
                    appliedPaths.setAccessible(false);
                }
            }
        }

        manager.setFilterChains(new LinkedHashMap<>());
        // 路径匹配器
        Map<String, String> filterChainDefinitionMap = getFilterChainDefinitionMap();

        //参考org.apache.shiro.spring.web.ShiroFilterFactoryBean#createFilterChainManager
        if (!CollectionUtils.isEmpty(filterChainDefinitionMap)) {
            for (Map.Entry<String, String> entry : filterChainDefinitionMap.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue();
                manager.createChain(url, chainDefinition);
            }
        }
        Map<String, NamedFilterList> filterChains = manager.getFilterChains();
        // create the default chain, to match anything the path matching would have missed
        manager.createDefaultChain("/**"); // TODO this assumes ANT path matching, which might be OK here
    }

    public Map<String,String> getFilterChainDefinitionMap(){
        //匹配数据库
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        List<SysPermission> sysPermissions = sysPermissionServiceBase.list();
        List<SysResourcePermission> sysResourcePermissions = sysResourcePermissionServiceBase.list(new LambdaQueryWrapper<SysResourcePermission>().
                orderByDesc(SysResourcePermission::getMatchOrder, SysResourcePermission::getOperateTime, SysResourcePermission::getId));
        HashMap<Integer,SysPermission> permissionMap=new HashMap<>();
        for(SysPermission sysPermission:sysPermissions){
            Integer id=sysPermission.getId();
            permissionMap.put(id,sysPermission);
        }
        for(SysResourcePermission sysResourcePermission:sysResourcePermissions){
            String path=sysResourcePermission.getPath();
            String permissionIds = sysResourcePermission.getPermissionIds();
            if(filterChainDefinitionMap.containsKey(path)||permissionIds==null){
                continue;
            }
            StringBuilder sb=new StringBuilder();
            String[] split = permissionIds.split(",");
            for(String str:split){
                try{
                    Integer num=Integer.valueOf(str);
                    SysPermission sysPermission = permissionMap.get(num);
                    if(sysPermission!=null){
                        sb.append(sysPermission.getCode()+",");
                    }
                }catch (Exception e){
                }
            }
            if(sb.length()>0){
                sb.deleteCharAt(sb.length()-1);
                filterChainDefinitionMap.put(path,"loginFilter,perms["+sb.toString()+"]");
            }
        }
        return filterChainDefinitionMap;
    }
    
}

    

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 在 Spring Boot 中使用 shiro 配置自定义过滤器需要以下几个步骤: 1. 引入 shiro-spring-boot-starter 依赖: ``` <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.1</version> </dependency> ``` 2. 创建自定义过滤器: ``` public class CustomFilter extends AccessControlFilter { @Override protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception { // 在这里实现自定义的过滤逻辑,返回 true 表示通过过滤器,返回 false 表示未通过过滤器 return true; } @Override protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { // 如果 isAccessAllowed 返回 false,则会进入到这里,可以在这里处理未通过过滤器的情况 return false; } } ``` 3. 配置 shiroFilterChainDefinition: ``` @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); // 添加自定义过滤器,其中 key 是过滤器名称,value 是该过滤器对应的路径 chainDefinition.addPathDefinition("/custom/**", "custom"); return chainDefinition; } ``` 4. 配置自定义过滤器: ``` @Bean("custom") public CustomFilter customFilter() { return new CustomFilter(); } ``` 5. 配置 shiro 的注解支持: ``` @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } ``` 完成以上步骤后,就可以在 Spring Boot 中使用 shiro 配置自定义过滤器了。 ### 回答2: 在 Spring Boot 中使用 Shiro 配置自定义过滤器分为三个步骤。 第一步,创建自定义过滤器类。可以通过实现 ShiroFilter 接口来创建自定义过滤器。在自定义过滤器中需要实现过滤规则,并对请求进行相应的处理。 第二步,配置 Shiro 过滤器链。在 Spring Boot 的配置类中,通过创建 ShiroFilterFactoryBean 对象来配置 Shiro过滤器链。可以使用 ShiroFilterChainDefinitionMap 对象来配置过滤器链,然后将该对象设置给 ShiroFilterFactoryBean。 第三步,启用 Shiro 过滤器。在 Spring Boot 的配置类中,通过创建 DefaultFilterChainManager 对象,并将该对象设置给 ShiroFilterFactoryBean,启用自定义过滤器。 有了以上三步,就可以在 Spring Boot 中使用 Shiro 配置自定义过滤器了。可以通过在自定义过滤器中实现过滤规则来对请求进行拦截或处理,然后在 Shiro 过滤器链中配置过滤器,最后启用该过滤器。这样就可以实现对请求的自定义过滤器处理。 值得注意的是,在使用 Shiro 进行自定义过滤器配置时,需要保证 Shiro配置文件中已经进行了相应的配置,包括认证和授权等相关配置。只有在正确配置的前提下,才能正确使用 Shiro 进行自定义过滤器配置。 ### 回答3: 在Spring Boot中使用Shiro配置自定义过滤器通常需要以下几个步骤: 1. 引入Shiro和Spring Boot依赖。在pom.xml文件中添加Shiro和Spring Boot Starter依赖: ``` <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 2. 创建自定义过滤器类。可以通过实现`javax.servlet.Filter`接口或者继承`org.apache.shiro.web.servlet.OncePerRequestFilter`类来创建自定义过滤器。例如,创建一个名为`CustomFilter`的自定义过滤器类: ``` public class CustomFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 过滤器逻辑处理 // ... filterChain.doFilter(request, response); } } ``` 3. 在Shiro配置类中注册自定义过滤器。创建一个Shiro配置类,并使用`@Configuration`注解标记为配置类。通过`@Bean`注解将自定义过滤器注册到Shiro过滤器链中。例如,在配置类`ShiroConfig`中注册`CustomFilter`: ``` @Configuration public class ShiroConfig { @Bean public FilterRegistrationBean<CustomFilter> customFilterRegistrationBean() { FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new CustomFilter()); registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 过滤器执行顺序 registrationBean.addUrlPatterns("/*"); // 过滤器路径 return registrationBean; } } ``` 4. 配置Shiro的过滤规则。在Shiro配置文件中,可以设置自定义过滤器的拦截规则。例如,在`shiro.ini`配置文件中,设置自定义过滤器的拦截规则: ``` [urls] /** = customFilter // 对所有请求都使用自定义过滤器 ``` 通过以上步骤,在Spring Boot中使用Shiro配置自定义过滤器就可以实现对特定请求的拦截和处理。在`CustomFilter`类的`doFilterInternal`方法中编写自定义的过滤器逻辑,例如鉴权、权限验证等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值