weixin_41768866
一直要学习
采纳率100%
2020-08-17 16:50

定时任务里调用SecurityUtils.getSubject()方法报错

ssm项目+shiro
配置了定时任务如下:

<bean name="Job" class="bpp.controller.Job"/>
    <bean id="job" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!-- 执行的类 -->
        <property name="targetObject">
            <ref bean="Job"/>
        </property>
        <!-- 类中的方法 -->
        <property name="targetMethod">
            <value>getData</value>
        </property>
    </bean>

想要在定时任务里获取当前登录信息,所以:
User user=(User) SecurityUtils.getSubject().getPrincipal();
但是报错:

Caused by: 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.
    at org.apache.shiro.SecurityUtils.getSecurityManager(SecurityUtils.java:123)
    at org.apache.shiro.subject.Subject$Builder.<init>(Subject.java:626)
    at org.apache.shiro.SecurityUtils.getSubject(SecurityUtils.java:56)

不知道为啥,其他controller都能用,排除网上说的filter没配好,就是定时任务没法获取,听说是Thread的问题,不知道为啥,有没有大佬知道。。。错在哪,怎么获取登录信息啊。。。多谢多谢

debug到源码,就是获取不到securityManager

 SecurityManager securityManager = ThreadContext.getSecurityManager();
        if (securityManager == null) {
            securityManager = SecurityUtils.securityManager;
        }
        if (securityManager == null) {
            String msg = "No SecurityManager accessible to the calling code, either bound to the " +
                    ThreadContext.class.getName() + " or as a vm static singleton.  This is an invalid application " +
                    "configuration.";
            throw new UnavailableSecurityManagerException(msg);
        }

就是ThreadContext.getSercurity为null,再往下走:

 public static SecurityManager getSecurityManager() {
        return (SecurityManager) get(SECURITY_MANAGER_KEY);
    }

虽然是打了断点,但是好像断点对定时任务没用,看不到具体的空值:

public static Object get(Object key) {
        if (log.isTraceEnabled()) {
            String msg = "get() - in thread [" + Thread.currentThread().getName() + "]";
            log.trace(msg);
        }

        Object value = getValue(key);
        if ((value != null) && log.isTraceEnabled()) {
            String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" +
                    key + "] " + "bound to thread [" + Thread.currentThread().getName() + "]";
            log.trace(msg);
        }
        return value;
    }

当前线程不可能获取不到,所以就是当前线程找不到指定的key但是,为啥,是因为定时任务给自己新开了一个独立的线程,而这个线程和用户登录的那个线程无关吗。。。唉,心累

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

4条回答

  • weixin_43836863 怀人 8月前

    先说,我不知道定时中怎么获取,但我认为你的方法有问题。
    1.定时任务是跑在服务端的任务调度,和有没有用户登录、用户登不登陆完全没关系
    2.SecurityUtils获取用户信息的使用,肯定要在一次网络请求的上下文中,不然连用户这个概念都找不到
    我觉得这个设计逻辑不正确,应该要换一下吧

    点赞 1 评论 复制链接分享
  • zhangpan_soft zhangpan_soft 8月前

    你应该是用的shiro框架,shiro框架这个方法可以在普通类中获取到的前提是,此为一个有效的http连接,或者tcp连接,而在定时任务里,不是http连接,也不是tcp连接,自然获取不到,

    点赞 1 评论 复制链接分享
  • EnseHeiKe Ense 1月前

    用spring的ApplicationContext.getBean(DefaultWebSecurityManager.calss);试试(如果你用的实现类是DefaultWebSecurityManager)

     

    点赞 评论 复制链接分享
  • en_joker 孤芳不自賞 8月前

    既然是idea,我建议你直接debug到源码。

    点赞 评论 复制链接分享