(window.webpackJsonp=window.webpackJsonp||[]).push([[622],{1053:function(e,t,n){"use strict";n.r(t);var c=n(56),r=Object(c.a)({},(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("h1",{attrs:{id:"并发支持"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#并发支持"}},[e._v("#")]),e._v(" 并发支持")]),e._v(" "),n("p",[e._v("在大多数环境中,安全性是以per"),n("code",[e._v("Thread")]),e._v("为基础存储的。这意味着,当在新的"),n("code",[e._v("Thread")]),e._v("上完成工作时,"),n("code",[e._v("SecurityContext")]),e._v("将丢失。 Spring 安全性提供了一些基础设施,以帮助用户更容易地实现这一点。 Spring 安全性为在多线程环境中使用 Spring 安全性提供了低层次的抽象。实际上,这是 Spring 安全性构建在["),n("code",[e._v("AsyncContext.start(Runnable)")]),e._v("]( Servlet-api.html#servletapi-start-runnable)和"),n("RouterLink",{attrs:{to:"/spring-security/mvc.html#mvc-async"}},[e._v("Spring MVC Async Integration")]),e._v("集成之上的。")],1),e._v(" "),n("h2",{attrs:{id:"在可撤销的情况下将证券转让"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#在可撤销的情况下将证券转让"}},[e._v("#")]),e._v(" 在可撤销的情况下将证券转让")]),e._v(" "),n("p",[e._v("Spring Security的并发支持中最基本的构建块之一是"),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v("。它包装了一个委托"),n("code",[e._v("Runnable")]),e._v(",以便用指定的"),n("code",[e._v("SecurityContext")]),e._v("为委托初始化"),n("code",[e._v("SecurityContextHolder")]),e._v("。然后,它调用委托Runnable确保在之后清除"),n("code",[e._v("SecurityContextHolder")]),e._v("。"),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v("看起来是这样的:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("public void run() {\ntry {\n\tSecurityContextHolder.setContext(securityContext);\n\tdelegate.run();\n} finally {\n\tSecurityContextHolder.clearContext();\n}\n}\n")])])]),n("p",[e._v("虽然非常简单,但它可以无缝地将SecurityContext从一个线程转移到另一个线程。这一点很重要,因为在大多数情况下,SecurityContextholder是以每个线程为基础的。例如,你可能使用了 Spring Security的["),n("code",[e._v("")]),e._v("](../acception/namespace/method-security.html#NSA-global-method-security)支持来保护你的某个服务。现在,你可以轻松地将当前"),n("code",[e._v("Thread")]),e._v("的"),n("code",[e._v("SecurityContext")]),e._v("传输到调用安全服务的"),n("code",[e._v("Thread")]),e._v("。下面是你如何做到这一点的一个示例:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("Runnable originalRunnable = new Runnable() {\npublic void run() {\n\t// invoke secured service\n}\n};\n\nSecurityContext context = SecurityContextHolder.getContext();\nDelegatingSecurityContextRunnable wrappedRunnable =\n\tnew DelegatingSecurityContextRunnable(originalRunnable, context);\n\nnew Thread(wrappedRunnable).start();\n")])])]),n("p",[e._v("上面的代码执行以下步骤:")]),e._v(" "),n("ul",[n("li",[n("p",[e._v("创建将调用我们的安全服务的"),n("code",[e._v("Runnable")]),e._v("。请注意,它并不了解 Spring 安全性")])]),e._v(" "),n("li",[n("p",[e._v("从"),n("code",[e._v("SecurityContextHolder")]),e._v("获取我们希望使用的"),n("code",[e._v("SecurityContext")]),e._v(",并初始化"),n("code",[e._v("DelegatingSecurityContextRunnable")])])]),e._v(" "),n("li",[n("p",[e._v("使用"),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v("创建线程")])]),e._v(" "),n("li",[n("p",[e._v("启动我们创建的线程")])])]),e._v(" "),n("p",[e._v("由于从"),n("code",[e._v("SecurityContextHolder")]),e._v("中使用"),n("code",[e._v("SecurityContext")]),e._v("创建"),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v("是很常见的,因此有一个用于它的快捷构造函数。以下代码与上述代码相同:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("Runnable originalRunnable = new Runnable() {\npublic void run() {\n\t// invoke secured service\n}\n};\n\nDelegatingSecurityContextRunnable wrappedRunnable =\n\tnew DelegatingSecurityContextRunnable(originalRunnable);\n\nnew Thread(wrappedRunnable).start();\n")])])]),n("p",[e._v("我们拥有的代码使用起来很简单,但仍然需要了解我们正在使用 Spring 安全性。在下一节中,我们将研究如何利用"),n("code",[e._v("委派安全环境专家")]),e._v("来隐藏我们正在使用 Spring 安全性的事实。")]),e._v(" "),n("h2",{attrs:{id:"delegatingsecuritycontextexecutor"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#delegatingsecuritycontextexecutor"}},[e._v("#")]),e._v(" DelegatingSecurityContextExecutor")]),e._v(" "),n("p",[e._v("在上一节中,我们发现使用"),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v("很容易,但并不理想,因为我们必须意识到 Spring 安全性才能使用它。让我们来看看"),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v("如何保护我们的代码不受我们正在使用 Spring 安全性的任何知识的影响。")]),e._v(" "),n("p",[n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v("的设计与"),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v("的设计非常相似,只是它接受一个委托"),n("code",[e._v("Executor")]),e._v("而不是一个委托"),n("code",[e._v("Runnable")]),e._v("。你可以在下面看到一个如何使用它的示例:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v('SecurityContext context = SecurityContextHolder.createEmptyContext();\nAuthentication authentication =\n\tnew UsernamePasswordAuthenticationToken("user","doesnotmatter", AuthorityUtils.createAuthorityList("ROLE_USER"));\ncontext.setAuthentication(authentication);\n\nSimpleAsyncTaskExecutor delegateExecutor =\n\tnew SimpleAsyncTaskExecutor();\nDelegatingSecurityContextExecutor executor =\n\tnew DelegatingSecurityContextExecutor(delegateExecutor, context);\n\nRunnable originalRunnable = new Runnable() {\npublic void run() {\n\t// invoke secured service\n}\n};\n\nexecutor.execute(originalRunnable);\n')])])]),n("p",[e._v("代码执行以下步骤:")]),e._v(" "),n("ul",[n("li",[n("p",[e._v("创建用于我们的"),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v("的"),n("code",[e._v("SecurityContext")]),e._v("。注意,在这个示例中,我们只需手工创建"),n("code",[e._v("SecurityContext")]),e._v("。然而,无论我们在哪里或如何获得"),n("code",[e._v("SecurityContext")]),e._v("都不重要(也就是说,如果我们愿意,我们可以从"),n("code",[e._v("SecurityContextHolder")]),e._v("获得它)。")])]),e._v(" "),n("li",[n("p",[e._v("创建一个DelegateExecutor,它负责执行提交的"),n("code",[e._v("Runnable")]),e._v("s")])]),e._v(" "),n("li",[n("p",[e._v("最后,我们创建一个"),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(",它负责用"),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v("包装传递到Execute方法中的任何runnable。然后,它将包装好的Runnable传递给DelegateExecutor。在此实例中,对于提交到我们的"),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v("的每个runnable,将使用相同的"),n("code",[e._v("SecurityContext")]),e._v("。如果我们运行的是需要由具有提升权限的用户运行的后台任务,那么这很好。")])]),e._v(" "),n("li",[n("p",[e._v("此时,你可能会问自己:“这是如何保护我的代码不受安全知识的影响的?”我们不需要在自己的代码中创建"),n("code",[e._v("SecurityContext")]),e._v("和"),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v(",而是可以插入一个已经初始化的"),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v("实例。")])])]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("@Autowired\nprivate Executor executor; // becomes an instance of our DelegatingSecurityContextExecutor\n\npublic void submitRunnable() {\nRunnable originalRunnable = new Runnable() {\n\tpublic void run() {\n\t// invoke secured service\n\t}\n};\nexecutor.execute(originalRunnable);\n}\n")])])]),n("p",[e._v("现在我们的代码不知道"),n("code",[e._v("SecurityContext")]),e._v("正在传播到"),n("code",[e._v("Thread")]),e._v(",然后运行"),n("code",[e._v("originalRunnable")]),e._v(",然后清除"),n("code",[e._v("SecurityContextHolder")]),e._v("。在本例中,使用相同的用户运行每个线程。如果我们希望在调用"),n("code",[e._v("SecurityContextHolder")]),e._v("时使用来自"),n("code",[e._v("executor.execute(Runnable)")]),e._v("的用户(即当前登录的用户)来处理"),n("code",[e._v("originalRunnable")]),e._v(",该怎么办?这可以通过从我们的"),n("code",[e._v("DelegatingSecurityContextExecutor")]),e._v("构造函数中删除"),n("code",[e._v("SecurityContext")]),e._v("参数来完成。例如:")]),e._v(" "),n("div",{staticClass:"language- extra-class"},[n("pre",{pre:!0,attrs:{class:"language-text"}},[n("code",[e._v("SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor();\nDelegatingSecurityContextExecutor executor =\n\tnew DelegatingSecurityContextExecutor(delegateExecutor);\n")])])]),n("p",[e._v("现在,每当执行"),n("code",[e._v("executor.execute(Runnable)")]),e._v("时,"),n("code",[e._v("SecurityContext")]),e._v("首先由"),n("code",[e._v("SecurityContextHolder")]),e._v("得到,然后"),n("code",[e._v("SecurityContext")]),e._v("用于创建我们的"),n("code",[e._v("DelegatingSecurityContextRunnable")]),e._v("。这意味着我们运行"),n("code",[e._v("Runnable")]),e._v("的用户与调用"),n("code",[e._v("executor.execute(Runnable)")]),e._v("代码的用户相同。")]),e._v(" "),n("h2",{attrs:{id:"spring-安全并发类"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#spring-安全并发类"}},[e._v("#")]),e._v(" Spring 安全并发类")]),e._v(" "),n("p",[e._v("请参考Javadoc,以获取与 Java 并发API和 Spring 任务抽象的附加集成。一旦你理解了前面的代码,它们就非常不言自明了。")]),e._v(" "),n("ul",[n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextCallable")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextExecutor")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextExecutorService")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextRunnable")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextScheduledExecutorService")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextSchedulingTaskExecutor")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextAsyncTaskExecutor")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextTaskExecutor")])])]),e._v(" "),n("li",[n("p",[n("code",[e._v("DelegatingSecurityContextTaskScheduler")])])])]),e._v(" "),n("p",[n("RouterLink",{attrs:{to:"/spring-security/index.html"}},[e._v("整合")]),n("RouterLink",{attrs:{to:"/spring-security/jackson.html"}},[e._v("Jackson")])],1)])}),[],!1,null,null,null);t.default=r.exports}}]);