当前位置: 代码网 > it编程>编程语言>Java > Spring Security异步无法获取用户认证信息的解决方法

Spring Security异步无法获取用户认证信息的解决方法

2024年09月14日 Java 我要评论
原因:spring security中的上下文securitycontext的管理策略有三种public class securitycontextholder { public static

原因:

spring security中的上下文securitycontext的管理策略有三种

public class securitycontextholder {
    public static final string mode_threadlocal = "mode_threadlocal";

    public static final string mode_inheritablethreadlocal = "mode_inheritablethreadlocal";

    public static final string mode_global = "mode_global";
}

默认的管理策略是:mode_threadlocal,对应的策略类是
org.springframework.security.core.context.threadlocalsecuritycontextholderstrategy

以下是 spring security 初始化策略的代码:

public class securitycontextholder {
    public static final string mode_threadlocal = "mode_threadlocal";

    public static final string mode_inheritablethreadlocal = "mode_inheritablethreadlocal";

    public static final string mode_global = "mode_global";
    // 获取系统配置的策略
    private static string strategyname = system.getproperty(system_property);
    // 预初始化策略
    private static securitycontextholderstrategy strategy;
    
    private static void initializestrategy() {
        if (mode_pre_initialized.equals(strategyname)) {
            assert.state(strategy != null, "when using " + mode_pre_initialized
                    + ", setcontextholderstrategy must be called with the fully constructed strategy");
            return;
        }
        if (!stringutils.hastext(strategyname)) {
            // set default
            strategyname = mode_threadlocal;
        }
        if (strategyname.equals(mode_threadlocal)) {
            strategy = new threadlocalsecuritycontextholderstrategy();
            return;
        }
        if (strategyname.equals(mode_inheritablethreadlocal)) {
            strategy = new inheritablethreadlocalsecuritycontextholderstrategy();
            return;
        }
        if (strategyname.equals(mode_global)) {
            strategy = new globalsecuritycontextholderstrategy();
            return;
        }
        // try to load a custom strategy
        try {
            class<?> clazz = class.forname(strategyname);
            constructor<?> customstrategy = clazz.getconstructor();
            strategy = (securitycontextholderstrategy) customstrategy.newinstance();
        }
        catch (exception ex) {
            reflectionutils.handlereflectionexception(ex);
        }
    }
}

threadlocalsecuritycontextholderstrategy 里保存context的方式是 threadlocal,threadlocal 子线程并不能获取父类线程的 threadlocalmap,
所以就导致了异步无法获取到用户认证信息。

final class threadlocalsecuritycontextholderstrategy implements securitycontextholderstrategy {

    private static final threadlocal<supplier<securitycontext>> contextholder = new threadlocal<>();

}

解决方法:

更改上下文的管理策略 securitycontextholderstrategy 为 mode_inheritablethreadlocal,即

inheritablethreadlocalsecuritycontextholderstrategy,里面保存上下文的方式是 inheritablethreadlocal,可以获取父线程的 threadlocalmap。

final class inheritablethreadlocalsecuritycontextholderstrategy implements securitycontextholderstrategy {

	private static final threadlocal<supplier<securitycontext>> contextholder = new inheritablethreadlocal<>();

}

inheritablethreadlocal可以获取到子线程信息‌,主要是因为它是threadlocal的一个子类,设计用来在父子线程间传递数据。
threadlocal变量通常只在当前线程中存在,并且每个线程都有其自己的threadlocalmap,
这样保证了线程间的数据隔离。然而,在某些情况下,我们需要父线程中的数据能够在由父线程创建的子线程中被访问,
这时就需要使用inheritablethreadlocal。
inheritablethreadlocal的实现机制使其能够在子线程中访问父线程的数据。具体来说,当父线程创建一个子线程时,
inheritablethreadlocal会采取措施确保子线程可以访问到父线程中设置的inheritablethreadlocal变量。
这通常涉及到在子线程的thread对象中复制父线程的threadlocalmap,从而使子线程能够访问到父线程中设置的变量。
这种机制允许在多线程环境中,特别是在使用线程池等场景下,实现父子线程间数据的传递和共享。
需要注意的是,虽然inheritablethreadlocal提供了在子线程中访问父线程数据的能力,但它并不适用于所有情况,
特别是在复杂的线程交互中可能需要更精细的控制。此外,使用inheritablethreadlocal时也需要注意避免内存泄漏等问题,因为如果不当使用,
它可能会导致资源的不当占用‌。

代码:

  • 1、可以在配置 security 的配置类中添加 bean
@configuration
@enablewebsecurity
public class securityconfig {
    @bean
    public methodinvokingfactorybean methodinvokingfactorybean() {
        methodinvokingfactorybean factorybean = new methodinvokingfactorybean();
        factorybean.settargetclass(securitycontextholder.class);
        factorybean.settargetmethod("setstrategyname");
        factorybean.setarguments(securitycontextholder.mode_inheritablethreadlocal);
        return factorybean;
    }
}
  • 2、可以在配置 security 的配置类中添加类初始化方式,会在注入 securitycontextholder 之后调用其中静态方法更改 securitycontextholderstrategy 的实现类
@configuration
@enablewebsecurity
public class securityconfig {
    @postcontruct
    public void init() {
        securitycontextholder.setstrategyname(securitycontextholder.mode_inheritablethreadlocal);
    }
}
  • 3、可以在启动项加上 -dspring.security.strategy=mode_inheritablethreadlocal 参数,启动时更改 securitycontextholderstrategy 的实现类

以上就是spring security异步无法获取用户认证信息的解决方法的详细内容,更多关于spring security异步无法获取信息的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com