并发支持
在大多数环境中,Security 是按每个 (per) 存储的。
这意味着,当在 new 上完成工作时,将丢失。
Spring Security 提供了一些基础设施来帮助用户更轻松地做到这一点。
Spring Security 为在多线程环境中使用 Spring Security 提供了低级抽象。
事实上,这就是 Spring Security 与 AsyncContext.start(Runnable) 和 Spring MVC 异步集成集成的基础。Thread
Thread
SecurityContext
DelegatingSecurityContextRunnable
Spring Security 的并发支持中最基本的构建块之一是 .
它包装一个委托,以便使用为委托指定的 进行初始化。
然后,它调用委托 Runnable 以确保清除 after.
它看起来像这样:DelegatingSecurityContextRunnable
Runnable
SecurityContextHolder
SecurityContext
SecurityContextHolder
DelegatingSecurityContextRunnable
-
Java
-
Kotlin
public void run() {
try {
SecurityContextHolder.setContext(securityContext);
delegate.run();
} finally {
SecurityContextHolder.clearContext();
}
}
fun run() {
try {
SecurityContextHolder.setContext(securityContext)
delegate.run()
} finally {
SecurityContextHolder.clearContext()
}
}
虽然非常简单,但它使 SecurityContext 从一个 Thread 无缝传输到另一个 Thread 成为可能。
这很重要,因为在大多数情况下,SecurityContextHolder基于每个线程起作用。
例如,您可能已经使用了 Spring Security 的 <global-method-security> 支持来保护您的一项服务。
您现在可以轻松地将 current 转移到调用 secured 服务的 。
您可以在下面找到如何执行此操作的示例:SecurityContext
Thread
Thread
-
Java
-
Kotlin
Runnable originalRunnable = new Runnable() {
public void run() {
// invoke secured service
}
};
SecurityContext context = SecurityContextHolder.getContext();
DelegatingSecurityContextRunnable wrappedRunnable =
new DelegatingSecurityContextRunnable(originalRunnable, context);
new Thread(wrappedRunnable).start();
val originalRunnable = Runnable {
// invoke secured service
}
val context: SecurityContext = SecurityContextHolder.getContext()
val wrappedRunnable = DelegatingSecurityContextRunnable(originalRunnable, context)
Thread(wrappedRunnable).start()
上面的代码执行以下步骤:
-
创建一个将调用我们的安全服务。 请注意,它不知道 Spring Security
Runnable
-
从 中获取我们希望使用的 ,并初始化
SecurityContext
SecurityContextHolder
DelegatingSecurityContextRunnable
-
使用 创建 Thread
DelegatingSecurityContextRunnable
-
启动我们创建的线程
由于使用 from the 创建一个 a 是很常见的,因此有一个 shortcut constructor for it。
以下代码与上面的代码相同:DelegatingSecurityContextRunnable
SecurityContext
SecurityContextHolder
-
Java
-
Kotlin
Runnable originalRunnable = new Runnable() {
public void run() {
// invoke secured service
}
};
DelegatingSecurityContextRunnable wrappedRunnable =
new DelegatingSecurityContextRunnable(originalRunnable);
new Thread(wrappedRunnable).start();
val originalRunnable = Runnable {
// invoke secured service
}
val wrappedRunnable = DelegatingSecurityContextRunnable(originalRunnable)
Thread(wrappedRunnable).start()
我们拥有的代码易于使用,但它仍然需要知道我们正在使用 Spring Security。
在下一节中,我们将了解如何利用它来隐藏我们正在使用 Spring Security 的事实。DelegatingSecurityContextExecutor
DelegatingSecurityContextExecutor
在上一节中,我们发现它很容易使用 ,但它并不理想,因为我们必须了解 Spring Security 才能使用它。
让我们看看如何保护我们的代码免受我们正在使用 Spring Security 的任何知识的影响。DelegatingSecurityContextRunnable
DelegatingSecurityContextExecutor
的设计与 的设计非常相似,只是它接受 delegate 而不是 delegate 。
您可以在下面看到如何使用它的示例:DelegatingSecurityContextExecutor
DelegatingSecurityContextRunnable
Executor
Runnable
-
Java
-
Kotlin
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication =
UsernamePasswordAuthenticationToken.authenticated("user","doesnotmatter", AuthorityUtils.createAuthorityList("ROLE_USER"));
context.setAuthentication(authentication);
SimpleAsyncTaskExecutor delegateExecutor =
new SimpleAsyncTaskExecutor();
DelegatingSecurityContextExecutor executor =
new DelegatingSecurityContextExecutor(delegateExecutor, context);
Runnable originalRunnable = new Runnable() {
public void run() {
// invoke secured service
}
};
executor.execute(originalRunnable);
val context: SecurityContext = SecurityContextHolder.createEmptyContext()
val authentication: Authentication =
UsernamePasswordAuthenticationToken("user", "doesnotmatter", AuthorityUtils.createAuthorityList("ROLE_USER"))
context.authentication = authentication
val delegateExecutor = SimpleAsyncTaskExecutor()
val executor = DelegatingSecurityContextExecutor(delegateExecutor, context)
val originalRunnable = Runnable {
// invoke secured service
}
executor.execute(originalRunnable)
该代码执行以下步骤:
-
创建要用于我们的 . 请注意,在此示例中,我们只是手动创建 . 但是,我们从哪里或如何获得 the 并不重要(即,如果我们愿意,我们可以从 the 获得它)。
SecurityContext
DelegatingSecurityContextExecutor
SecurityContext
SecurityContext
SecurityContextHolder
-
创建一个 delegateExecutor,负责执行提交的
Runnable
-
最后,我们创建一个 runnable,它负责包装任何传递给 execute 方法的 Runnable。 然后,它将包装好的 Runnable 传递给 delegateExecutor。 在这种情况下,将对提交给我们的 . 如果我们正在运行需要由具有提升权限的用户运行的后台任务,这很好。
DelegatingSecurityContextExecutor
DelegatingSecurityContextRunnable
SecurityContext
DelegatingSecurityContextExecutor
-
此时,您可能会问自己“这如何保护我的代码中有关 Spring Security 的任何知识?我们可以注入一个已经初始化的 .
SecurityContext
DelegatingSecurityContextExecutor
DelegatingSecurityContextExecutor
-
Java
-
Kotlin
@Autowired
private Executor executor; // becomes an instance of our DelegatingSecurityContextExecutor
public void submitRunnable() {
Runnable originalRunnable = new Runnable() {
public void run() {
// invoke secured service
}
};
executor.execute(originalRunnable);
}
@Autowired
lateinit var executor: Executor // becomes an instance of our DelegatingSecurityContextExecutor
fun submitRunnable() {
val originalRunnable = Runnable {
// invoke secured service
}
executor.execute(originalRunnable)
}
现在我们的代码不知道 the 正在传播到 ,然后运行 ,然后 被清除。
在此示例中,使用同一用户运行每个线程。
如果我们想使用调用时的用户(即当前登录的用户)来处理 ?
这可以通过从构造函数中删除参数来完成。
例如:SecurityContext
Thread
originalRunnable
SecurityContextHolder
SecurityContextHolder
executor.execute(Runnable)
originalRunnable
SecurityContext
DelegatingSecurityContextExecutor
-
Java
-
Kotlin
SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor();
DelegatingSecurityContextExecutor executor =
new DelegatingSecurityContextExecutor(delegateExecutor);
val delegateExecutor = SimpleAsyncTaskExecutor()
val executor = DelegatingSecurityContextExecutor(delegateExecutor)
现在,每当执行 时,首先由 获取,然后用于创建我们的 。
这意味着我们正在使用用于调用代码的同一用户运行我们的。executor.execute(Runnable)
SecurityContext
SecurityContextHolder
SecurityContext
DelegatingSecurityContextRunnable
Runnable
executor.execute(Runnable)
Spring Security 并发类
请参阅 Javadoc 以获取与 Java 并发 API 和 Spring Task 抽象的其他集成。 一旦您理解了前面的代码,它们就不言自明了。
-
DelegatingSecurityContextCallable
-
DelegatingSecurityContextExecutor
-
DelegatingSecurityContextExecutorService
-
DelegatingSecurityContextRunnable
-
DelegatingSecurityContextScheduledExecutorService
-
DelegatingSecurityContextSchedulingTaskExecutor
-
DelegatingSecurityContextAsyncTaskExecutor
-
DelegatingSecurityContextTaskExecutor
-
DelegatingSecurityContextTaskScheduler