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

本文解决了使用Shiro框架配置多角色权限时遇到的问题。通过重写RolesAuthorizationFilter的isAccessAllowed方法,允许用户拥有角色列表中的任意一个角色即可访问受保护资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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()方法,所以推测按照原先的代码逻辑是当前用户需要拥有角色列表中所有的角色名,才可以拥有访问权限。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jz_Stu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值