Dobbo集成Shiro消费者调用服务时SecurityManager为null的问题

问题描述:

最近在学习关于Dubbo集成Shiro,设想用服务提供者提供关于用户的认证与授权工作,消费者通过服务调用的方式实现上述功能。然而在我进行测试的时候,消费者可以成功的通过dubbo获取到服务者提供的业务实现类,但是在执行业务的时候会报错;同样的方法,我在服务提供者中进行测试是完全ok的,但是使用消费者调用就会报如下错误:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton.  This is an invalid application configuration. 

问题解决:

通过Spring的工厂,获取对应的SecurityManager对象,并手动赋值给SecurityUtils。此时问题解决。

服务提供代码:

/**
 * @description:  服务提供者——用户基础服务实现类
 * @author:JessyHuang
 * @date:2021/10/28 9:42
 */
@Slf4j
@Service
public class BaseUserServiceImpl implements BaseUserService {


    @Autowired
    private GgMenuService ggMenuService;

    @Override
    public ApiResult login(String username, String password) {

        ApiResult apiResult = ApiResult.create();
        SecurityManager securityManager = SpringUtils.getBean(SecurityManager.class);
        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();
    

 SpringUtils工具类:

@Component
@Slf4j
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    /**
     * Spring在bean初始化后会判断是不是ApplicationContextAware的子类
     * 如果该类是,setApplicationContext()方法,会将容器中Application做为参数传入进去
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
        if(SpringUtils.applicationContext == null){
            SpringUtils.applicationContext = applicationContext;
        }
        log.info("ApplicationContext配置成功,applicationContext对象:{}", SpringUtils.applicationContext);
    }


    public static ApplicationContext getApplicationContext(){
        return applicationContext;
    }

    /**
     * 通过name返回指定的Bean
     * @param beanClass
     * @param <T>
     * @return
     */
    public static<T> T getBean(Class<T> beanClass){
        return applicationContext.getBean(beanClass);
    }

    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    public static<T> T getBean(String name, Class<T> beanClass){
        return getApplicationContext().getBean(name,beanClass);
    }
}

问题分析:

通过报错信息反馈可以得知,是缺失了Shiro的SecurityManager组件,通过断点debug也可以证明上述观点。然而,奇怪的是同样的业务实现类,如果直接调用服务提供者是完全正常的,但是通过消费者调用服务提供者则异常。百度类似的问题,清一色的博客转载,而且大部分的解决方案都是指向关于shiro配置中没有自定义SecurityManager组件,或者是与shiro过滤器相关的解决方案,完全是不适用的。

这里我分析原因是:Shiro的机制是通过Filter的方式,对请求进行过滤限制,这里的请求通常情况下使用的是Http请求,也就是我通过postman或者前端程序通过restful的方式发送请求,这时会根据我们自定义的shiro过滤器的规则,对请求进行访问的限制。而现在通过微服务的方式,服务调用由dubbo进行接管,请求的方式也变为了rpc方式,这样的情况也就导致了消费者的请求无法被shiro的过滤器过滤。由此我产生了两个思路:

1.缺失的组件是由Spring的工厂创建的,SecurityManager的构建过程是在ShiroConfig.java这个配置类中,那么就不在对外提供new对象的方式进行构建了,所以这个时候需要从spring的容器中获取bean对象,此时需要创建一个SpringUtils工具类,指定对应的类对象来获取对应的实例对象,在问题解决过程中已经将工具类代码贴出来了。

2.既然shiro需要管理所有的请求,那么尝试让shiro的过滤器能够接管dubbo的rpc请求,尝试使用自定义过滤器的方式,并让shiro的过滤器的创建时机优先于自定义过滤器,但是考虑到过滤器的工作原理还是只能过滤到http请求,所以这边我经过一些尝试就放弃了。(如果是我的操作和思路不对,希望大家能耐心指正共同学习)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值