OAuth 2.0 Client
OAuth 2.0 Client 特性提供了对 OAuth 2.0授权框架中定义的 Client 角色的支持。
在高层次,可用的核心特征是:
Authorization Grant support
- Authorization Code
- Refresh Token
- Client Credentials
- Resource Owner Password Credentials
- JWT Bearer
- Token Exchange
Client Authentication support
HTTP Client support
- 用于 Servlet 环境的 WebClient 集成(用于请求受保护的资源)
Oauth2Client () DSL 为定制 OAuth 2.0 Client 使用的核心组件提供了许多配置选项。另外,HttpSecurity.oauth2Client().authorizationCodeGrant()
启用授权代码授权的自定义。
下面的代码显示了 HttpSecurity.oauth2Client () DSL 提供的完整配置选项:
OAuth2 Client Configuration Options
@Configuration
@EnableWebSecurity
public class OAuth2ClientSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.oauth2Client(oauth2 -> oauth2
.clientRegistrationRepository(this.clientRegistrationRepository())
.authorizedClientRepository(this.authorizedClientRepository())
.authorizedClientService(this.authorizedClientService())
.authorizationCodeGrant(codeGrant -> codeGrant
.authorizationRequestRepository(this.authorizationRequestRepository())
.authorizationRequestResolver(this.authorizationRequestResolver())
.accessTokenResponseClient(this.accessTokenResponseClient())
)
);
return http.build();
}
}
除了 HttpSecurity.oauth2Client () DSL 之外,还支持 XML 配置。
下面的代码显示了security namespace中可用的完整配置选项:
OAuth2 Client XML Configuration Options
<http>
<oauth2-client client-registration-repository-ref="clientRegistrationRepository"
authorized-client-repository-ref="authorizedClientRepository"
authorized-client-service-ref="authorizedClientService">
<authorization-code-grant
authorization-request-repository-ref="authorizationRequestRepository"
authorization-request-resolver-ref="authorizationRequestResolver"
access-token-response-client-ref="accessTokenResponseClient"/>
</oauth2-client>
</http>
OAuth2AuthorizedClientManager 与一个或多个 OAuth2AuthorizedClientProvider 协作,负责管理 OAuth 2.0客户端的授权(或重新授权)。
下面的代码显示了如何注册一个 OAuth2AuthorizedClientManager@Bean 并将其与一个 OAuth2AuthorizedClientProvider 组合关联的示例,该组合提供uthorization_code``, ``refresh_token``, ``client_credentials``, and ``password
授予类型的支持:
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
Section Summary
- Core Interfaces and Classes
- OAuth2 Authorization Grants
- OAuth2 Client Authentication
- OAuth2 Authorized Clients
Core Interfaces and Classes
本节介绍 SpringSecurity 提供的 OAuth2核心接口和类。
ClientRegistration
ClientRegistry 是用 OAuth 2.0或 OpenID Connect 1.0 Provider 注册的客户机的表示形式。
ClientRegistry 对象保存信息,如客户机 ID、客户机机密、授权授予类型、重定向 URI、作用域、授权 URI、令牌 URI 和其他详细信息。
ClientRegistry 及其属性定义如下:
public final class ClientRegistration {
private String registrationId; //1
private String clientId; //2
private String clientSecret; //3
private ClientAuthenticationMethod clientAuthenticationMethod; //4
private AuthorizationGrantType authorizationGrantType; //5
private String redirectUri; //6
private Set<String> scopes; //7
private ProviderDetails providerDetails;
private String clientName; //8
public class ProviderDetails {
private String authorizationUri; //9
private String tokenUri; //10
private UserInfoEndpoint userInfoEndpoint;
private String jwkSetUri; //11
private String issuerUri; //12
private Map<String, Object> configurationMetadata;//13
public class UserInfoEndpoint {
private String uri; //14
private AuthenticationMethod authenticationMethod;//15
private String userNameAttributeName; //16
}
}
}
RegistrationId
: 唯一标识ClientRegistration
的 ID。ClientId
: 客户端标识符。clientSecret
: 客户端密码。ClientAuthenticationMethod
: 用于通过提供程序对客户端进行身份验证的方法。支持的值是 client_secret_basic, client_secret_post, private_key_jwt, client_secret_jwt and none (public clients).AuthorizationGrantType
: OAuth 2.0授权框架定义了四种授权授权类型。支持的值包括 authorization_code,
client_credentials,
password 以及扩展授权类型 urn:ietf:params:oauth:grant-type:jwt-bearer。RedirectUri
: 在最终用户对客户端进行身份验证和授权访问之后,Authorization Server 将最终用户的用户代理重定向到的客户端注册的重定向 URI。scopes
: 客户端在授权请求流(如 openid、电子邮件或配置文件)中请求的作用域。ClientName
: 用于客户端的描述性名称。该名称可用于某些场景,例如在自动生成的登录页面中显示客户端名称时。AuthorizationUri
: 授权服务器的授权端点 URI。TokenUri
: 授权服务器的令牌端点 URI。JwkSetUri
: 用于从 Authorization Server 检索 JSON Web Key (JWK) Set 的 URI,其中包含用于验证 ID 令牌的 JSON Web Signature (JWS)和(可选) UserInfo Response 的单密钥。IsserUri
: 返回 OpenID Connect 1.0提供程序或 OAuth 2.0 Authorization Server 的发行者标识符 URI。ConfigationMetadata
: OpenID 提供程序配置信息。只有在配置了 Spring Boot 属性 Spring.security.oauth2.client.Provider. [ provision erId ] . isserUri 时,此信息才可用。(userInfoEndpoint) URI
: 用于访问经过身份验证的最终用户的声明和属性的 UserInfo Endpoint URI。(userInfoEndpoint) enticationMethod
: 向 UserInfo 端点发送访问令牌时使用的身份验证方法。支持的值是头、表单和查询。UserNameAttributeName
: 在 UserInfo Response 中返回的引用最终用户的 Name 或 Identifier 的属性的名称。
通过使用 OpenID 连接提供程序的配置端点或授权服务器的元数据端点的发现,最初可以配置 ClientRegistration
。
ClientRegistration
以这种方式为配置 ClientRegistration
提供了方便的方法,如下所示:
ClientRegistration clientRegistration =
ClientRegistrations.fromIssuerLocation("https://idp.example.com/issuer").build();
前面的代码查询按序列、 idp.example.com/issuer/.well-known/openid-configuration、 idp.example.com/.well-known/openid-configuration/issuer 和 idp.example.com/.well-known/oauth-authorization-server/issuer 进行,在第一个查询结束时返回200个响应。
作为替代方案,您可以使用 ClientRegistrations.forOidcIssuerLocation ()仅查询 OpenID 连接提供程序的 Configuration 端点。
ClientRegistrationRepository
ClientRegistrationRepository 充当 OAuth 2.0/OpenID Connect 1.0 ClientRegistration
(s)的存储库。
客户端注册信息最终由关联的 AuthorizationServer 存储和拥有。此存储库提供了检索主客户端注册信息子集的能力,这些信息存储在 AuthorizationServer 中。
Spring Boot 自动配置绑定 spring.security.oauth2.client.registration.[registrationId] 的实例,然后在 ClientRegistrationRepository 中组合每个 ClientRegistration实例。
ClientRegistrationRepository 的默认实现是 InmemyClientRegistrationRepository。
自动配置还在 ApplicationContext 中将 ClientregistrationRepository 注册为一个@Bean,以便在应用程序需要的时候,它可以用于依赖注入。
下面的清单显示了一个示例:
@Controller
public class OAuth2ClientController {
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@GetMapping("/")
public String index() {
ClientRegistration oktaRegistration =
this.clientRegistrationRepository.findByRegistrationId("okta");
...
return "index";
}
}
OAuth2AuthorizedClient
OAuth2AuthorizedClient 是授权客户端的表示形式。当最终用户(资源所有者)授予客户端访问其受保护资源的权限时,客户端被认为是被授权的。
OAuth2AuthorizedClient 用于将 OAuth2AccessToken (和可选的 OAuth2RefreshToken)关联到 ClientRegistry (客户端)和资源所有者,后者是授予授权的主要最终用户。
OAuth2AuthorizedClientRepository and OAuth2AuthorizedClientService
OAuth2AuthorizedClientRepository 负责在 Web 请求之间保存 OAuth2AuthorizedClient (s) ,而 OAuth2AuthorizedClientService 的主要角色是在应用程序级别管理 OAuth2AuthorizedClient (s)。
从开发人员的角度来看,OAuth2AuthorizedClientRepository 或 OAuth2AuthorizedClientService 提供了查找与客户端关联的 OAuth2AccessToken 的能力,以便可以使用它来启动受保护的资源请求。
下面的清单显示了一个示例:
@Controller
public class OAuth2ClientController {
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@GetMapping("/")
public String index(Authentication authentication) {
OAuth2AuthorizedClient authorizedClient =
this.authorizedClientService.loadAuthorizedClient("okta", authentication.getName());
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
...
return "index";
}
}
OAuth2AuthorizedClientService 的默认实现是 InMemorial yOAuth2AuthorizedClientService,它在内存中存储 OAuth2AuthorizedClient 对象。
或者,您可以配置 JDBC 实现 JdbcOAuth2AuthorizedClientService 以在数据库中持久存储 OAuth2AuthorizedClient 实例。
JdbcOAuth2AuthorizedClientService 依赖于 OAuth 2.0 Client Schema.。
OAuth2AuthorizedClientManager and OAuth2AuthorizedClientProvider
OAuth2AuthorizedClientManager 负责 OAuth2AuthorizedClient (s)的全面管理。
主要职责包括:
- 使用 OAuth2AuthorizedClientProvider 授权(或重新授权) OAuth2.0客户端。
- 委托 OAuth2AuthorizedClient 的持久性,通常使用 OAuth2AuthorizedClientService 或 OAuth2AuthorizedClientRepository。
- 当 OAuth 2.0客户端已经成功授权(或重新授权)时,委托给 OAuth2AuthorizationSuccess Handler。
- 当 OAuth 2.0客户端无法授权(或重新授权)时,委托给 OAuth2AuthorizationFallureHandler。
OAuth2AuthorizedClientProvider 实现了授权(或重新授权) OAuth 2.0客户端的策略。实现通常实现授权授予类型,例如 authorization_code
, client_credentials
, and others.
OAuth2AuthorizedClientManager 的默认实现是 DefaultOAuth2AuthorizedClientManager,它与 OAuth2AuthorizedClientProvider 相关联,OAuth2AuthorizedClientProvider 可以使用基于委托的组合支持多种授权授权类型。可以使用 OAuth2AuthorizedClientProviderBuilder 配置和生成基于委托的组合。
下面的代码显示了如何配置和构建 OAuth2AuthorizedClientProvider 组合的示例,该组合提供对authorization_code,
refresh_token,
client_credentials, and
password授予类型的支持:
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
当授权尝试成功时,DefaultOAuth2AuthorizedClientManager 委托给 OAuth2AuthorizationSuccess Handler,该委托(默认情况下)通过 OAuth2AuthorizedClientRepository 保存 OAuth2AuthorizedClient。在重新授权失败的情况下(例如,刷新令牌不再有效) ,先前保存的 OAuth2AuthorizedClient 将通过 RemoveAuthorizedClientOAuthizationAuthorureHandler 从 OAuth2AuthorizedClientRepository 中删除。您可以通过 setAuthorizationSuccess Handler (OAuth2AuthorizationSuccess Handler)和 setAuthorizationfalureHandler (OAuth2AuthorizationfalureHandler)定制默认行为。
DefaultOAuth2AuthorizedClientManager 还与类型为 Function <OAuth2AuthorizeRequest,Map < String,Object > 的 contextAttributesMapper 相关联,后者负责将属性从 OAuth2AuthorizeRequest 映射到与 OAuth2AuthorizationContext 相关联的属性映射。当您需要为 OAuth2AuthorizedClientProvider 提供必需的(受支持的)属性时,例如 PasswordOAuth2AuthorizedClientProvider 要求资源所有者的用户名和密码在 OAuth2AuthorizationContext.getAttritribute ()中可用时,这会很有用。
下面的代码显示 contextAttributesMapper 的示例:
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
return authorizedClientManager;
}
private Function<OAuth2AuthorizeRequest, Map<String, Object>> contextAttributesMapper() {
return authorizeRequest -> {
Map<String, Object> contextAttributes = Collections.emptyMap();
HttpServletRequest servletRequest = authorizeRequest.getAttribute(HttpServletRequest.class.getName())