shrio实现自定义的角色自定义filter

bug:

使用shiro对某一个接口路径进行角色限制的时候,发现只要设置了多角色之后权限失效的问题。
shiro配置的部分代码如下:

	//DefaultFilter
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager){
        System.out.println("shiroFilter============4");
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);
        //配置登录、登录成功、失败等跳转接口
        bean.setLoginUrl("/login");
        bean.setSuccessUrl("/index");
        bean.setUnauthorizedUrl("/unauthorized");

        //配置权限规则
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //index的路径使用authc的权限认证(DefaultFilter,每一个都是一个拦截类)
        filterChainDefinitionMap.put("/index","authc");//需要身份认证
        filterChainDefinitionMap.put("/","authc");//需要身份认证
        filterChainDefinitionMap.put("/login","anon");//忽略
        filterChainDefinitionMap.put("/loginUser","anon");//忽略
        //RolesAuthorizationFilter,具有这个角色的用户才可以访问
        filterChainDefinitionMap.put("/search","roles[admin,user]");
        //PermissionsAuthorizationFilter,具有这个权限的用户才可以访问
        filterChainDefinitionMap.put("/edit","perms[edit]");
        filterChainDefinitionMap.put("/druid/**","anon");//将druid的请求全部放开
        filterChainDefinitionMap.put("/**","user");//当前是否登录用户
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }

配置中这一行(filterChainDefinitionMap.put("/search",“roles[admin,user]”);)如果换成单一角色可以正常使用,但是配置多角色之后会导致权限失效,进入“/unauthorized”接口


排查过程:

在网上翻了些资料,并没有找到特别合适的,基本都是在老的xml配置中进行权限角色分配,有些干脆没写。后面得到一点启发,去看了(RolesAuthorizationFilter)源码,通过debug定位到了DelegatingSubject中的hasAllRoles方法,但是遇到了一个问题,在这里记录一下,暂时走不下去了。


public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {

        Subject subject = getSubject(request, response);
        String[] rolesArray = (String[]) mappedValue;

        if (rolesArray == null || rolesArray.length == 0) {
            //no roles specified, so nothing to check - allow access.
            return true;
        }

        Set<String> roles = CollectionUtils.asSet(rolesArray);
        return subject.hasAllRoles(roles);
    }
public boolean hasAllRoles(Collection<String> roleIdentifiers) {
        return hasPrincipals() && securityManager.hasAllRoles(getPrincipals(), roleIdentifiers);
    }
    
     protected boolean hasPrincipals() {
        return !isEmpty(getPrincipals());
    }

卡在了hasPrincipals()这个方法,按理说应该是非空的,然后走到securityManager.hasAllRoles()这个方法,但是debug走不过去,不知道是不是找错实现类的原因。


解决方法:

源码走不过去,发现不了原因,但是RolesAuthorizationFilter类中有一个isAccessAllowed()方法,大体就是判断当前用户中是否存在这个角色名称,既然发现不了问题,就绕开重写这个方法,定义一个新的规则。
1、重写拦截器代码:其中主要就是修改了最后一个步骤,直接进行角色的判断

package com.shiro.filter;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.util.Set;

/**
 * Created by Jzs on 2021/8/2
 * 角色过滤器
 */
public class RoleFilter extends RolesAuthorizationFilter {
    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {

        Subject subject = getSubject(request, response);
        String[] rolesArray = (String[]) mappedValue;

        if (rolesArray == null || rolesArray.length == 0) {
            //no roles specified, so nothing to check - allow access.
            return true;
        }

        Set<String> roles = CollectionUtils.asSet(rolesArray);
        for (String role : roles) {
            if(subject.hasRole(role)){
                return true;
            }
        }
        return false;
    }
}

2、将自定义的拦截器注入到shiro的配置中
修改后的配置代码:经测试可正常使用

	@Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager){
        System.out.println("shiroFilter============4");
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);
        // 存放自定义的filter
        LinkedHashMap<String, Filter> filtersMap = new LinkedHashMap<>();
        // 配置自定义角色认证过滤器
        filtersMap.put("roles", new RoleFilter());
        bean.setFilters(filtersMap);
        
        //配置登录、登录成功、失败等跳转接口
        bean.setLoginUrl("/login");
        bean.setSuccessUrl("/index");
        bean.setUnauthorizedUrl("/unauthorized");

        //配置权限规则
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //index的路径使用authc的权限认证(DefaultFilter,每一个都是一个拦截类)
        filterChainDefinitionMap.put("/index","authc");//需要身份认证
        filterChainDefinitionMap.put("/","authc");//需要身份认证
        filterChainDefinitionMap.put("/login","anon");//忽略
        filterChainDefinitionMap.put("/loginUser","anon");//忽略
        //RolesAuthorizationFilter,具有这个角色的用户才可以访问
        filterChainDefinitionMap.put("/search","roles[admin,user]");
        //PermissionsAuthorizationFilter,具有这个权限的用户才可以访问
        filterChainDefinitionMap.put("/edit","perms[edit]");
        filterChainDefinitionMap.put("/druid/**","anon");//将druid的请求全部放开
        filterChainDefinitionMap.put("/**","user");//当前是否登录用户
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }

猜测(待验证):

可以看到其实只是修改了代码中的hasAllRoles()方法为hasRole()方法,所以推测按照原先的代码逻辑是当前用户需要拥有角色列表中所有的角色名,才可以拥有访问权限。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答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`方法中编写自定义过滤器逻辑,例如鉴权、权限验证等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jz_Stu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值