具有默认系统身份验证/用户的SecurityContext [英] SecurityContext with default System authentication/user

查看:98
本文介绍了具有默认系统身份验证/用户的SecurityContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的spring应用程序中,我希望SecurityContext始终包含Authentication.如果不是常规的UsernamePasswordAuthenticationToken,它将是描述系统用户"的PreAuthenticatedAuthenticationToken.这在需要用户的不同系统功能内具有原因.为了避免在没有用户上下文的情况下进行特殊处理,我只想添加系统上下文.恕我直言,这也与单一责任原则有关.

In my spring application, I would like that a SecurityContext always holds an Authentication. If it's not a regular UsernamePasswordAuthenticationToken, it will be a PreAuthenticatedAuthenticationToken describing the "system user." This has reasons within different system function which requires a user. To avoid a special treatment if there is no user context, I merely want to add the system context. IMHO, this has also to do with the single responsibility principle.

要实现此目的,我可以简单地实现自己的SecurityContextHolderStrategy,并使用SecurityContextHolder.setStrategyName(MyStrategyClassName);

To achieve this, I can simply implement my own SecurityContextHolderStrategy and set the it to the SecurityContextHolder with SecurityContextHolder.setStrategyName(MyStrategyClassName);

出现问题了:

默认SecurityContextHolderStrategyThreadLocalSecurityContextHolderStrategy.我对这项策略及其运作方式感到满意.我唯一要更改的是getContext()方法.

The default SecurityContextHolderStrategy is the ThreadLocalSecurityContextHolderStrategy. I'm happy with this strategy and how it works. The only thing which I would change is the getContext() method.

public SecurityContext getContext() {
    SecurityContext ctx = CONTEXT_HOLDER.get();

    if (ctx == null) {
        ctx = createEmptyContext();
        CONTEXT_HOLDER.set(ctx);
    }
    return ctx;
}

public SecurityContext getContext() {
    SecurityContext ctx = CONTEXT_HOLDER.get();

    if (ctx == null) {
        ctx = createEmptyContext();
        Authentication authentication = new PreAuthenticatedAuthenticationToken("system", null);
        authentication.setAuthenticated(true);
        ctx.setAuthentication(authentication);
        CONTEXT_HOLDER.set(ctx);
    }
    return ctx;
}

不可能,因为ThreadLocalSecurityContextHolderStrategy类不是 public .当然,我可以简单地将ThreadLocalSecurityContextHolderStrategy的代码复制粘贴到我自己的SecurityContextHolderStrategy中,并以自己想要的方式实现getContext()方法.但这给了我感觉,好像我走错了路.

This is not possible as the ThreadLocalSecurityContextHolderStrategy class is not public. Of course I can simply copy paste the code of the ThreadLocalSecurityContextHolderStrategy into my own SecurityContextHolderStrategy and implement the getContext() method the way I want. But this gives me the feeling as I might be on the wrong path.

我如何获得新的SecurityContext的默认系统用户" Authentication?

How could I achieve a "system user" Authentication as default for a new SecurityContext?

更新

我的上述方法显然不是一种解决方案,因为它极具侵入性,会创建冗余代码,并且需要在Web过滤器链中进行特殊处理.但这应该使我了解自己的目标. 我正在寻找一种解决方案,该解决方案应尽可能与本机spring安全性实现无缝结合. 我的问题是我对侵入性方法非常了解.如何解决好呢?我无法想象我是这个要求的第一人.还是整个概念完全错误?

My approach above is apparently not a solution as it is extremely invasive, creates redundant code and needs special treatment within the web filter chain. But it should give an understanding of my goal. I'm looking for a solution, which fits as seamless as possible to the native spring security implementation. My problem is that I'm quite fixed on the invasive approach. How can this solve nicely? I cannot imagine that I'm the first person with this requirement. Or is the whole concept altogether wrong?

推荐答案

如果获得了以下解决方案,那么该解决方案非常精巧,不会碰撞或干扰任何东西. 通常,在两种情况下,我将进行null身份验证:

If got the following solution, which is quite slick and doesn't collide or interfere with anything. In generall I have two situations where I'll have a null authentication:

  1. 主系统线程.
  2. 执行预定任务. (可以根据具体情况使用MODE_INHERITABLETHREADLOCAL配置解决,更多详细信息请参见下文.)
  1. Main system thread.
  2. Executing scheduled task. (Could be solved with MODE_INHERITABLETHREADLOCAL config depending on use case, more details see below.)

解决方案1.

这仍然使主系统线程出现问题.只需在系统启动时设置上下文,即可非常轻松地处理此问题.另外,我将SecurityContextHolder配置为使用InheritableThreadLocalSecurityContextHolderStrategy,以便所有子线程都将继承SecurityContext.每当应用程序上下文刷新时,我们都会进行此设置.允许在运行与安全上下文相关的测试时使用@DirtiesContext.

This still leaves the problem with the main system thread. This is very easily handled by just setting the context on system start up. Also I configure the SecurityContextHolder to use a InheritableThreadLocalSecurityContextHolderStrategy so all child threads will inherit the SecurityContext. We make this setting everytime the application context refreshes. This allows to use @DirtiesContext when running security context related tests..

@Component
public class SecurityContextConfiguration {

    @EventListener
    public void setupSecurityContext(ContextRefreshedEvent event) {
    SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
    SecurityContextHolder.getContext().setAuthentication(new SystemAuthentication());
    }
}

解决方案2.

因为我已经用MODE_INHERITABLETHREADLOCAL配置了SecurityContextHolder.预定线程将影响其父Securitycontext.在我的用例中,这是不需要的,因为这意味着以下内容: 如果计划的任务是在用户操作期间初始化的,则它将在用户SecurityContext下运行.由于我不想在系统重新启动时放弃计划的任务,因此我将其保留下来.这将导致与用户SecurityContext初始化之前相同的任务,在重新启动时将与系统SecurityContext一起初始化.这产生了矛盾.因此,我也配置了调度程序.

As I have configured the SecurityContextHolder with MODE_INHERITABLETHREADLOCAL. A scheduled thread will inheriet his parent Securitycontext. In my use case this is not wanted as this would mean the following: If a scheduled task gets initialized dua a user action, it would run under the users SecurityContext. As I do not want to loose a scheduled task on system reboot, I'll persist them. Which would lead to that the same task which was before initialized with the users SecurityContext, will get intitialize with the systems SecurityContext on reboot. This generates an inconsitence. Therefor I configure my scheduler too.

我只需将@Scheduled注释配置为由DelegatingSecurityContextScheduledExecutorService执行,就可以设置SecurityContext.

I simply configure the @Scheduled annotation to be executed by a DelegatingSecurityContextScheduledExecutorService allowing me to set a SecurityContext.

@EnableScheduling
@Configuration
public class SystemAwareSchedulerConfiguration implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
    taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean
    public ScheduledExecutorService taskExecutor() {
    ScheduledExecutorService delegateExecutor = Executors.newSingleThreadScheduledExecutor();
    SecurityContext schedulerContext = createSchedulerSecurityContext();
    return new DelegatingSecurityContextScheduledExecutorService(delegateExecutor, schedulerContext);
    }

    private SecurityContext createSchedulerSecurityContext() {
    SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
    securityContext.setAuthentication(new SystemAuthentication());
    return securityContext;
    }

}

使用这两种配置,如果线程不是由Web容器初始化的,我将始终具有SystemUser上下文.

With this two configurations, I'll always will have a SystemUser context if the thread wasn't initialized by the web container.

这篇关于具有默认系统身份验证/用户的SecurityContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆