556.42a17364.js 6.5 KB
Newer Older
茶陵後's avatar
茶陵後 已提交
1
(window.webpackJsonp=window.webpackJsonp||[]).push([[556],{985:function(e,t,a){"use strict";a.r(t);var n=a(56),r=Object(n.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"oauth2-0-资源服务器多租户"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#oauth2-0-资源服务器多租户"}},[e._v("#")]),e._v(" OAuth2.0 资源服务器多租户")]),e._v(" "),a("h2",{attrs:{id:"多重租赁"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#多重租赁"}},[e._v("#")]),e._v(" 多重租赁")]),e._v(" "),a("p",[e._v("当存在多个用于验证由某个租户标识符控制的承载令牌的策略时,资源服务器被认为是多租户的。")]),e._v(" "),a("p",[e._v("例如,你的资源服务器可能接受来自两个不同授权服务器的承载令牌。或者,你的授权服务器可能表示多个发行者。")]),e._v(" "),a("p",[e._v("在每种情况下,都需要做两件事,以及与选择如何做这些事情相关的权衡:")]),e._v(" "),a("ol",[a("li",[a("p",[e._v("解决租户")])]),e._v(" "),a("li",[a("p",[e._v("宣传租户")])])]),e._v(" "),a("h3",{attrs:{id:"通过索赔来解决承租人的问题"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#通过索赔来解决承租人的问题"}},[e._v("#")]),e._v(" 通过索赔来解决承租人的问题")]),e._v(" "),a("p",[e._v("区分租户的一种方法是通过签发人索赔。由于发行者声明伴随着已签名的 JWTS,因此可以使用"),a("code",[e._v("JwtIssuerReactiveAuthenticationManagerResolver")]),e._v("来完成此操作,如下所示:")]),e._v(" "),a("p",[e._v("爪哇")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver\n    ("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo");\n\nhttp\n    .authorizeExchange(exchanges -> exchanges\n        .anyExchange().authenticated()\n    )\n    .oauth2ResourceServer(oauth2 -> oauth2\n        .authenticationManagerResolver(authenticationManagerResolver)\n    );\n')])])]),a("p",[e._v("Kotlin")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('val customAuthenticationManagerResolver = JwtIssuerReactiveAuthenticationManagerResolver("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo")\n\nreturn http {\n    authorizeExchange {\n        authorize(anyExchange, authenticated)\n    }\n    oauth2ResourceServer {\n        authenticationManagerResolver = customAuthenticationManagerResolver\n    }\n}\n')])])]),a("p",[e._v("这很好,因为发行者端点是懒洋洋地加载的。实际上,对应的"),a("code",[e._v("JwtReactiveAuthenticationManager")]),e._v("只有在发送了与对应的发行者的第一个请求时才被实例化。这允许应用程序启动,该应用程序独立于已启动和可用的那些授权服务器。")]),e._v(" "),a("h4",{attrs:{id:"动态租户"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#动态租户"}},[e._v("#")]),e._v(" 动态租户")]),e._v(" "),a("p",[e._v("当然,你可能不希望每次添加新租户时都重新启动应用程序。在这种情况下,你可以使用"),a("code",[e._v("JwtIssuerReactiveAuthenticationManagerResolver")]),e._v("实例的存储库配置"),a("code",[e._v("ReactiveAuthenticationManager")]),e._v("实例,你可以在运行时对其进行编辑,如下所示:")]),e._v(" "),a("p",[e._v("爪哇")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("private Mono<ReactiveAuthenticationManager> addManager(\n\t\tMap<String, ReactiveAuthenticationManager> authenticationManagers, String issuer) {\n\n\treturn Mono.fromCallable(() -> ReactiveJwtDecoders.fromIssuerLocation(issuer))\n            .subscribeOn(Schedulers.boundedElastic())\n            .map(JwtReactiveAuthenticationManager::new)\n            .doOnNext(authenticationManager -> authenticationManagers.put(issuer, authenticationManager));\n}\n\n// ...\n\nJwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver =\n        new JwtIssuerReactiveAuthenticationManagerResolver(authenticationManagers::get);\n\nhttp\n    .authorizeExchange(exchanges -> exchanges\n        .anyExchange().authenticated()\n    )\n    .oauth2ResourceServer(oauth2 -> oauth2\n        .authenticationManagerResolver(authenticationManagerResolver)\n    );\n")])])]),a("p",[e._v("Kotlin")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("private fun addManager(\n        authenticationManagers: MutableMap<String, ReactiveAuthenticationManager>, issuer: String): Mono<JwtReactiveAuthenticationManager> {\n    return Mono.fromCallable { ReactiveJwtDecoders.fromIssuerLocation(issuer) }\n            .subscribeOn(Schedulers.boundedElastic())\n            .map { jwtDecoder: ReactiveJwtDecoder -> JwtReactiveAuthenticationManager(jwtDecoder) }\n            .doOnNext { authenticationManager: JwtReactiveAuthenticationManager -> authenticationManagers[issuer] = authenticationManager }\n}\n\n// ...\n\nvar customAuthenticationManagerResolver = JwtIssuerReactiveAuthenticationManagerResolver(authenticationManagers::get)\nreturn http {\n    authorizeExchange {\n        authorize(anyExchange, authenticated)\n    }\n    oauth2ResourceServer {\n        authenticationManagerResolver = customAuthenticationManagerResolver\n    }\n}\n")])])]),a("p",[e._v("在这种情况下,构造"),a("code",[e._v("JwtIssuerReactiveAuthenticationManagerResolver")]),e._v("时,要使用一种策略来获得给定发行人的"),a("code",[e._v("ReactiveAuthenticationManager")]),e._v("。这种方法允许我们在运行时从存储库中添加和删除元素(在代码片段中显示为"),a("code",[e._v("Map")]),e._v(")。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("简单地获取任何发行者并从中构造"),a("code",[e._v("ReactiveAuthenticationManager")]),e._v("将是不安全的。"),a("br"),e._v("发行者应该是代码可以从可信来源(如允许的发行者列表)验证的发行者。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[a("RouterLink",{attrs:{to:"/spring-security/opaque-token.html"}},[e._v("不透明令牌")]),a("RouterLink",{attrs:{to:"/spring-security/bearer-tokens.html"}},[e._v("不记名代币")])],1)])}),[],!1,null,null,null);t.default=r.exports}}]);