在前一节中,我们发现使用delegatingsecuritytycontextrunable很容易,但这并不理想,因为我们必须了解Spring Security才能使用它。让我们看一下DelegatingSecurityContextExecutor如何保护我们的代码免受我们使用的任何Spring Security知识的影响。
DelegatingSecurityContextExecutor的设计与delegatingsecuritycontextrunable的设计非常相似,只是它接受委托执行器Executor 而不是委托可运行Runnable,。您可以在下面看到如何使用它的示例:
1 SecurityContext context = SecurityContextHolder.createEmptyContext(); 2 Authentication authentication = new UsernamePasswordAuthenticationToken("user","doesnotmatter", AuthorityUtils.createAuthorityList("ROLE_USER")); 4 context.setAuthentication(authentication); 5 6 SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor(); 8 DelegatingSecurityContextExecutor executor = new DelegatingSecurityContextExecutor(delegateExecutor, context); 10 11 Runnable originalRunnable = new Runnable() { 12 public void run() { 13 // invoke secured service 14 } 15 }; 16 17 executor.execute(originalRunnable);
该代码执行以下步骤:
创建要用于我们的委托的安全上下文。请注意,在本例中,我们只是手工创建了SecurityContext。然而,我们从哪里或如何获得安全上下文并不重要(即,如果我们愿意,我们可以从安全上下文持有者那里获得它)。
创建一个委托执行器,负责执行提交的Runnable
s
最后,我们创建了一个DelegatingSecurityContextExecutor,它负责包装任何传递到带有delegatingsecuritycontextrunable的执行方法中的Runnable。然后,它将包装好的可运行Runnable 对象传递给委托执行器delegateExecutor。在这种情况下,相同的安全上下文将用于提交给我们的DelegatingSecurityContextExecutor的每个可运行文件。如果我们正在运行后台任务,而这些任务需要由拥有更高权限的用户来运行,这就很好了
此时,您可能会问自己“这是如何保护我的代码不了解Spring Security的?”我们不需要在自己的代码中创建SecurityContext和DelegatingSecurityContextExecutor,而是可以注入一个已经初始化的DelegatingSecurityContextExecutor实例。
1 @Autowired 2 private Executor executor; // becomes an instance of our DelegatingSecurityContextExecutor 3 4 public void submitRunnable() { 5 Runnable originalRunnable = new Runnable() { 6 public void run() { 7 // invoke secured service 8 } 9 }; 10 executor.execute(originalRunnable); 11 }
现在,我们的代码不知道安全上下文SecurityContext
正在被传播到线程,然后执行originalRunnable
,然后清除安全上下文持有者SecurityContextHolder
。在这个例子中,相同的用户被用来执行每个线程。如果我们在调用executor.execute(Runnable)时想使用SecurityContextHolder中的用户,该怎么办?(即当前登录的用户)处理originalRunnable?这可以通过从我们的DelegatingSecurityContextExecutor构造函数中删除SecurityContext参数来实现。例如:
1 SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor(); 2 DelegatingSecurityContextExecutor executor = new DelegatingSecurityContextExecutor(delegateExecutor);
现在,无论何时executor.execute(Runnable)执行,安全上下文SecurityContext
首先由安全上下文持有者SecurityContextHolder 获得,然后该安全上下文SecurityContext用于创建我们的委托安全上下文可运行DelegatingSecurityContextRunnable。这意味着我们用调用执行器的同一个用户执行我们的可运行代码executor.execute(Runnable)。