![](/img/trans.png)
[英]An Authentication object was not found in the SecurityContext on swagger
[英]SecurityContext with default System authentication/user
在我的spring應用程序中,我希望SecurityContext
始終擁有Authentication
。 如果它不是常規的UsernamePasswordAuthenticationToken
,則它將是描述“系統用戶”的PreAuthenticatedAuthenticationToken
。 這具有需要用戶的不同系統功能的原因。 如果沒有用戶上下文,為了避免特殊處理,我只想添加系統上下文。 恕我直言,這也與單一責任原則有關。
為此,我可以簡單地實現自己的SecurityContextHolderStrategy
並使用SecurityContextHolder.setStrategyName(MyStrategyClassName);
將其設置為SecurityContextHolder
SecurityContextHolder.setStrategyName(MyStrategyClassName);
現在來問題:
默認的SecurityContextHolderStrategy
是ThreadLocalSecurityContextHolderStrategy
。 我很滿意這個策略及其運作方式。 我唯一要改變的是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
身份驗證:
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.