簡體   English   中英

具有默認系統身份驗證/用戶的SecurityContext

[英]SecurityContext with default System authentication/user

在我的spring應用程序中,我希望SecurityContext始終擁有Authentication 如果它不是常規的UsernamePasswordAuthenticationToken ,則它將是描述“系統用戶”的PreAuthenticatedAuthenticationToken 這具有需要用戶的不同系統功能的原因。 如果沒有用戶上下文,為了避免特殊處理,我只想添加系統上下文。 恕我直言,這也與單一責任原則有關。

為此,我可以簡單地實現自己的SecurityContextHolderStrategy並使用SecurityContextHolder.setStrategyName(MyStrategyClassName);將其設置為SecurityContextHolder SecurityContextHolder.setStrategyName(MyStrategyClassName);

現在來問題:

默認的SecurityContextHolderStrategyThreadLocalSecurityContextHolderStrategy 我很滿意這個策略及其運作方式。 我唯一要改變的是getContext()方法。

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()方法。 但這給了我一種感覺,因為我可能走錯了路。

我如何實現“系統用戶” Authentication作為新SecurityContext默認Authentication

更新

我的上述方法顯然不是解決方案,因為它極具侵入性,會產生冗余代碼,需要在Web過濾器鏈中進行特殊處理。 但它應該讓我理解我的目標。 我正在尋找一種解決方案,它盡可能地與原生彈簧安全實現無縫結合。 我的問題是我對入侵方法非常關注。 這怎么能很好地解決? 我無法想象我是第一個有此要求的人。 或者整個概念完全錯了?

如果得到以下解決方案,這是非常光滑,不會碰撞或干擾任何事情。 一般來說,我有兩種情況,我將有一個null身份驗證:

  1. 主系統線程。
  2. 執行計划任務。 (可根據用例使用MODE_INHERITABLETHREADLOCAL配置解決,更多詳細信息請參見下文。)

解決方案1。

這仍然是主系統線程的問題。 只需在系統啟動時設置上下文即可輕松處理。 另外,我將SecurityContextHolder配置為使用InheritableThreadLocalSecurityContextHolderStrategy以便所有子線程都將繼承SecurityContext 每次應用程序上下文刷新時,我們都會進行此設置。 這允許在運行安全上下文相關測試時使用@DirtiesContext

@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進行初始化。 這會產生不一致。 因此我也配置了我的調度程序。

我只是將@Scheduled注釋配置為由DelegatingSecurityContextScheduledExecutorService執行,允許我設置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上下文。

createEmptyContext()創建填充的上下文聽起來不對:o)

正如這里所說,“一旦請求被認證, 身份驗證通常將存儲在由SecurityContextHolder管理的線程本地SecurityContext中,由正在使用的身份驗證機制 。”,我寧願擴展UsernamePasswordAuthenticationFilter並覆蓋attemptAuthentication如果用戶名密碼驗證失敗,請設置PreAuthenticatedAuthenticationToken

編輯

我認為對於系統內部任務,它取決於它們執行的方式。 對於Executor ,有一個示例設置上下文,如上所述在運行這些執行的線程中:

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

private SecurityContext createSchedulerSecurityContext() {
    SecurityContext context = SecurityContextHolder.createEmptyContext();

    Authentication authentication = new PreAuthenticatedAuthenticationToken("system", null);
    authentication.setAuthenticated(true);
    context.setAuthentication(authentication);

    return context;
}

創建此bean的@Configuration實現了SchedulingConfigurer

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM