641.70155ce7.js 13.2 KB
Newer Older
茶陵後's avatar
茶陵後 已提交
1
(window.webpackJsonp=window.webpackJsonp||[]).push([[641],{1072:function(e,t,r){"use strict";r.r(t);var a=r(56),n=Object(a.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h1",{attrs:{id:"oauth2-0不记名代币"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#oauth2-0不记名代币"}},[e._v("#")]),e._v(" OAuth2.0不记名代币")]),e._v(" "),r("h2",{attrs:{id:"不记名令牌解析"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#不记名令牌解析"}},[e._v("#")]),e._v(" 不记名令牌解析")]),e._v(" "),r("p",[e._v("默认情况下,Resource Server在"),r("code",[e._v("Authorization")]),e._v("头中查找承载令牌。然而,这可以通过几种方式进行定制。")]),e._v(" "),r("h3",{attrs:{id:"从自定义标头读取不记名令牌"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#从自定义标头读取不记名令牌"}},[e._v("#")]),e._v(" 从自定义标头读取不记名令牌")]),e._v(" "),r("p",[e._v("例如,你可能需要从自定义报头读取承载令牌。为了实现这一点,你可以将"),r("code",[e._v("DefaultBearerTokenResolver")]),e._v("公开为 Bean,或者将一个实例连接到DSL中,正如你在下面的示例中所看到的那样:")]),e._v(" "),r("p",[e._v("例1.自定义承载令牌标头")]),e._v(" "),r("p",[e._v("Java")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("@Bean\nBearerTokenResolver bearerTokenResolver() {\n    DefaultBearerTokenResolver bearerTokenResolver = new DefaultBearerTokenResolver();\n    bearerTokenResolver.setBearerTokenHeaderName(HttpHeaders.PROXY_AUTHORIZATION);\n    return bearerTokenResolver;\n}\n")])])]),r("p",[e._v("Kotlin")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("@Bean\nfun bearerTokenResolver(): BearerTokenResolver {\n    val bearerTokenResolver = DefaultBearerTokenResolver()\n    bearerTokenResolver.setBearerTokenHeaderName(HttpHeaders.PROXY_AUTHORIZATION)\n    return bearerTokenResolver\n}\n")])])]),r("p",[e._v("XML")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('<http>\n    <oauth2-resource-server bearer-token-resolver-ref="bearerTokenResolver"/>\n</http>\n\n<bean id="bearerTokenResolver"\n        class="org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver">\n    <property name="bearerTokenHeaderName" value="Proxy-Authorization"/>\n</bean>\n')])])]),r("p",[e._v("或者,在提供者同时使用自定义头和值的情况下,你可以使用"),r("code",[e._v("HeaderBearerTokenResolver")]),e._v("")]),e._v(" "),r("h3",{attrs:{id:"从窗体参数读取承载令牌"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#从窗体参数读取承载令牌"}},[e._v("#")]),e._v(" 从窗体参数读取承载令牌")]),e._v(" "),r("p",[e._v("或者,你可能希望从一个表单参数读取令牌,这可以通过配置"),r("code",[e._v("DefaultBearerTokenResolver")]),e._v("来实现,如下所示:")]),e._v(" "),r("p",[e._v("例2.表单参数承载令牌")]),e._v(" "),r("p",[e._v("Java")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver();\nresolver.setAllowFormEncodedBodyParameter(true);\nhttp\n    .oauth2ResourceServer(oauth2 -> oauth2\n        .bearerTokenResolver(resolver)\n    );\n")])])]),r("p",[e._v("Kotlin")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("val resolver = DefaultBearerTokenResolver()\nresolver.setAllowFormEncodedBodyParameter(true)\nhttp {\n    oauth2ResourceServer {\n        bearerTokenResolver = resolver\n    }\n}\n")])])]),r("p",[e._v("XML")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('<http>\n    <oauth2-resource-server bearer-token-resolver-ref="bearerTokenResolver"/>\n</http>\n\n<bean id="bearerTokenResolver"\n        class="org.springframework.security.oauth2.server.resource.web.HeaderBearerTokenResolver">\n    <property name="allowFormEncodedBodyParameter" value="true"/>\n</bean>\n')])])]),r("h2",{attrs:{id:"承载令牌传播"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#承载令牌传播"}},[e._v("#")]),e._v(" 承载令牌传播")]),e._v(" "),r("p",[e._v("既然你的资源服务器已经验证了令牌,那么将其传递给下游服务可能会很方便。对于"),r("code",[e._v("[ServletBearerExchangeFilterFunction](https://docs.spring.io/spring-security/site/docs/5.6.2/api/org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServletBearerExchangeFilterFunction.html)")]),e._v(",这非常简单,你可以在下面的示例中看到它:")]),e._v(" "),r("p",[e._v("Java")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("@Bean\npublic WebClient rest() {\n    return WebClient.builder()\n            .filter(new ServletBearerExchangeFilterFunction())\n            .build();\n}\n")])])]),r("p",[e._v("Kotlin")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("@Bean\nfun rest(): WebClient {\n    return WebClient.builder()\n            .filter(ServletBearerExchangeFilterFunction())\n            .build()\n}\n")])])]),r("p",[e._v("当上面的"),r("code",[e._v("WebClient")]),e._v("用于执行请求时, Spring Security将查找当前的"),r("code",[e._v("Authentication")]),e._v("并提取任何"),r("code",[e._v("[AbstractOAuth2Token](https://docs.spring.io/spring-security/site/docs/5.6.2/api/org/springframework/security/oauth2/core/AbstractOAuth2Token.html)")]),e._v("凭据。然后,它将在"),r("code",[e._v("Authorization")]),e._v("头中传播该令牌。")]),e._v(" "),r("p",[e._v("例如:")]),e._v(" "),r("p",[e._v("Java")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('this.rest.get()\n        .uri("https://other-service.example.com/endpoint")\n        .retrieve()\n        .bodyToMono(String.class)\n        .block()\n')])])]),r("p",[e._v("Kotlin")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('this.rest.get()\n        .uri("https://other-service.example.com/endpoint")\n        .retrieve()\n        .bodyToMono<String>()\n        .block()\n')])])]),r("p",[e._v("将调用"),r("code",[e._v("[https://other-service.example.com/endpoint](https://other-service.example.com/endpoint)")]),e._v(",为你添加承载令牌"),r("code",[e._v("Authorization")]),e._v("头。")]),e._v(" "),r("p",[e._v("在需要重写此行为的地方,你只需自己提供标题,就像这样:")]),e._v(" "),r("p",[e._v("Java")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('this.rest.get()\n        .uri("https://other-service.example.com/endpoint")\n        .headers(headers -> headers.setBearerAuth(overridingToken))\n        .retrieve()\n        .bodyToMono(String.class)\n        .block()\n')])])]),r("p",[e._v("Kotlin")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('this.rest.get()\n        .uri("https://other-service.example.com/endpoint")\n        .headers{  headers -> headers.setBearerAuth(overridingToken)}\n        .retrieve()\n        .bodyToMono<String>()\n        .block()\n')])])]),r("p",[e._v("在这种情况下,过滤器将向后退,只需将请求转发到Web筛选链的其余部分。")]),e._v(" "),r("table",[r("thead",[r("tr",[r("th"),e._v(" "),r("th",[e._v(""),r("a",{attrs:{href:"https://docs.spring.io/spring-security/site/docs/5.6.2/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("OAuth2.0客户端过滤功能"),r("OutboundLink")],1),e._v("不同,如果令牌过期,此筛选函数不尝试更新令牌。"),r("br"),e._v("要获得此级别的支持,请使用OAuth2.0客户端筛选。")])])]),e._v(" "),r("tbody")]),e._v(" "),r("h3",{attrs:{id:"resttemplate支持"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#resttemplate支持"}},[e._v("#")]),e._v(" "),r("code",[e._v("RestTemplate")]),e._v("支持")]),e._v(" "),r("p",[e._v("目前还没有"),r("code",[e._v("RestTemplate")]),e._v(""),r("code",[e._v("ServletBearerExchangeFilterFunction")]),e._v("等价物,但是你可以使用自己的拦截器非常简单地传播请求的承载令牌:")]),e._v(" "),r("p",[e._v("Java")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("@Bean\nRestTemplate rest() {\n\tRestTemplate rest = new RestTemplate();\n\trest.getInterceptors().add((request, body, execution) -> {\n\t\tAuthentication authentication = SecurityContextHolder.getContext().getAuthentication();\n\t\tif (authentication == null) {\n\t\t\treturn execution.execute(request, body);\n\t\t}\n\n\t\tif (!(authentication.getCredentials() instanceof AbstractOAuth2Token)) {\n\t\t\treturn execution.execute(request, body);\n\t\t}\n\n\t\tAbstractOAuth2Token token = (AbstractOAuth2Token) authentication.getCredentials();\n\t    request.getHeaders().setBearerAuth(token.getTokenValue());\n\t    return execution.execute(request, body);\n\t});\n\treturn rest;\n}\n")])])]),r("p",[e._v("Kotlin")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("@Bean\nfun rest(): RestTemplate {\n    val rest = RestTemplate()\n    rest.interceptors.add(ClientHttpRequestInterceptor { request, body, execution ->\n        val authentication: Authentication? = SecurityContextHolder.getContext().authentication\n        if (authentication != null) {\n            execution.execute(request, body)\n        }\n\n        if (authentication!!.credentials !is AbstractOAuth2Token) {\n            execution.execute(request, body)\n        }\n\n        val token: AbstractOAuth2Token = authentication.credentials as AbstractOAuth2Token\n        request.headers.setBearerAuth(token.tokenValue)\n        execution.execute(request, body)\n    })\n    return rest\n}\n")])])]),r("table",[r("thead",[r("tr",[r("th"),e._v(" "),r("th",[e._v(""),r("a",{attrs:{href:"https://docs.spring.io/spring-security/site/docs/5.6.2/api/org/springframework/security/oauth2/client/OAuth2AuthorizedClientManager.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("OAuth2.0授权客户经理"),r("OutboundLink")],1),e._v("不同的是,如果令牌过期,这个过滤器拦截器不会尝试更新令牌。"),r("br"),e._v("要获得这种级别的支持,请使用"),r("RouterLink",{attrs:{to:"/client/index.html#oauth2client"}},[e._v("OAuth2.0授权客户经理")]),e._v("创建一个拦截器。")],1)])]),e._v(" "),r("tbody")]),e._v(" "),r("h2",{attrs:{id:"承载令牌失败"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#承载令牌失败"}},[e._v("#")]),e._v(" 承载令牌失败")]),e._v(" "),r("p",[e._v("不记名令牌可能由于多种原因而无效。例如,令牌可能不再是活动的。")]),e._v(" "),r("p",[e._v("在这种情况下,资源服务器抛出一个"),r("code",[e._v("InvalidBearerTokenException")]),e._v("。与其他异常一样,这会导致一个OAuth2.0承载令牌错误响应:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('HTTP/1.1 401 Unauthorized\nWWW-Authenticate: Bearer error_code="invalid_token", error_description="Unsupported algorithm of none", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"\n')])])]),r("p",[e._v("此外,它以"),r("code",[e._v("AuthenticationFailureBadCredentialsEvent")]),e._v("的形式发布,你可以像这样"),r("RouterLink",{attrs:{to:"/authentication/events.html#servlet-events"}},[e._v("在你的应用程序中监听")]),e._v(":")],1),e._v(" "),r("p",[e._v("Java")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("@Component\npublic class FailureEvents {\n\t@EventListener\n    public void onFailure(AuthenticationFailureBadCredentialsEvent badCredentials) {\n\t\tif (badCredentials.getAuthentication() instanceof BearerTokenAuthenticationToken) {\n\t\t    // ... handle\n        }\n    }\n}\n")])])]),r("p",[e._v("Kotlin")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("@Component\nclass FailureEvents {\n    @EventListener\n    fun onFailure(badCredentials: AuthenticationFailureBadCredentialsEvent) {\n        if (badCredentials.authentication is BearerTokenAuthenticationToken) {\n            // ... handle\n        }\n    }\n}\n")])])]),r("p",[r("RouterLink",{attrs:{to:"/spring-security/multitenancy.html"}},[e._v("多租约")]),r("RouterLink",{attrs:{to:"/saml2/index.html"}},[e._v("SAML2")])],1)])}),[],!1,null,null,null);t.default=n.exports}}]);