在spring security 中对OAuth2的支持主要是对 OAuth2协议4个角色中对,客户端 (Client) 、资源服务器 (Resource Server) 的集成支持。
OAuth2 Client
Authorization Code Grant 流程
对流程稍加改造后,可以实现通过第三方服务授权
user agent:resource owner的代理,必须能执行url重定向,一般是浏览器,app
client:OAUTH2.O Client,用来获取resource owner授权的token
authorization server:授权服务器,用于验证client,获取resource owner授权及签发token
- 用户通过user agent 发送登录请求
- client 响应提供授权服务的选项,
- 用户选自己适合的授权服务选项
- client 响应重定向到authorization server rul ,携带client标识,凭据,授权类型及resource owner 授权后返回client url
- 重定向到authorization server
- authorization server 请求授权
- 用户通过user agent 授权
- authorization server 响应重定向client url, 携带resource owner 授权码
- user agent 重定向到client,
- client 请求authorization server 签发token
- authorization server 签发token
- 返回token到user agent
登录过虑器
HttpSecurity.oauth2login() 要求用户通过OAuth2登录,在OpenID Connect 1.0 中提供了一个名为id_token的特殊令牌,旨在为OAuth2客户端提供执行用户身份验证和登录用户的能力。
DefaultLoginPageGeneratingFilter:是在配置SecurityFilterChain 是通过HttpSecurity.oauth2Login()配置的一个Security Filter,其主要作用是
- 自动生成oauth2 login 页面,显示配置的ClientRegistration
- 利用身份验证者管理器进行身份验证者并生成授权客户端(OAuth2AuthorizedClient)
- 授权客户端大保存到OAuth2AuthorizedClientRepository and OAuth2AuthorizedClientService中
ClientRegistration 是代表client 中注册的OAuth 2.0 or OpenID Connect 1.0的提供者,包含client id, client secret, authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details
ClientRegistrationRepository 用于存储和提供ClientRegistration对象。默认实现类是InMemoryClientRegistrationRepository
OAuth2AuthorizedClient 代表一个已授权客户端。当终端用户(资源所有者)授予客户端访问其受保护资源的授权时,客户端被认为是被授权的
OAuth2AuthorizedClientRepository and OAuth2AuthorizedClientService 用于存储和提供OAuth2AuthorizedClient 对象,OAuth2AuthorizedClientRepository 是一个管理web 请求级的OAuth2AuthorizedClient 对象(一般非web中请求时获取不token),OAuth2AuthorizedClientService 是管理应用级的OAuth2AuthorizedClient
OAuth2AuthorizedClientManager : OAuth2AuthorizedClientManager 的实现类全面管理授权客户端OAuth2AuthorizedClient),可以用于获取访问OAuth2 Resource Server的内容token,主要作用:
- 通过OAuth2AuthorizedClientProvider的实现类获取授权。
- 管理OAuth2AuthorizedClient的持久性,通常使用OAuth2AuthorizedClientService或OAuth2AuthorizedClientRepository。
OAuth2AuthorizedClientProvider: 用于获取授权客户端(OAuth2AuthorizedClient)
授权重定向过虑器
OAuth2AuthorizationRequestRedirectFilter:此Security Filter,主要用是:
- 利用OAuth2AuthorizationRequestResolver从web请求中的ClientRegistration 创建一个OAuth2AuthorizationRequest对象,将根据此对象返回重定向authorization url(授权url) 到user agent。
- 利用AuthorizationRequestRepository保存删除OAuth2AuthorizationRequest
OAuth2AuthorizationRequestResolver:从web请求中的ClientRegistration创建一个OAuth2AuthorizationRequest,默认实现类是DefaultOAuth2AuthorizationRequestResolver,可以创建新的实现类来自定义OAuth2AuthorizationRequest,例如添加新参数等
AuthorizationRequestRepository负责从发起授权请求到接收授权响应(回调)期间OAuth2AuthorizationRequest的持久化。默认实现类是OAuth2AuthorizationRequest,是将OAuth2AuthorizationRequest 保存在AuthorizationRequestRepository。
token 获取(身份验证者)
获取token,基本上spring security 身份验证一致,登录过虑器使用身份验证者管理器获取身份验证者OAuth2LoginAuthenticationProvider
OAuth2LoginAuthenticationProvider:有两作用:
- 利用OAuth2AuthorizationCodeAuthenticationProvider获取token,OAuth2AuthorizationCodeAuthenticationProvider 也是利用OAuth2AccessTokenResponseClient 获取token
- 利用OAuth2UserService 获取用户信息,并利用GrantedAuthoritiesMapper 将用用户授权信息转换为 GrantedAuthority 列表对象
OAuth2AccessTokenResponseClient:负责使用授权凭证交换token,目前还是使用RestTemplate 来与Authorization Server 交互,可以通过OAuth2AccessTokenResponseClient 配置使用的RestTemplate,
- 其为Authorization Code类型授权的实现类是DefaultAuthorizationCodeTokenResponseClient 负现将Authorization Code 交换成Access Token,DefaultAuthorizationCodeTokenResponseClient来实现在交换请求前后实实现一些个性需求,
- 其为refresh_token类型授权的实现类是DefaultRefreshTokenTokenResponseClient,
- 其为client_credentials类型授权的实现类是DefaultClientCredentialsTokenResponseClient,负现将 Client Credentials 交换成Access Token
OAuth2UserService:从UserInfo Endpoint 获取用户信息,为OAuth 2.0默认实现类是DefaultOAuth2UserService,为OpenID Connect 1.0默认实现类是OidcUserService,
GrantedAuthritiesMapper:将用用户信息转换为 GrantedAuthority 列表对象,转换用户还可以使用
客户端认证(Client Authentication Support)
使用HTTP Basic(client_secret_basic)、client credentials(client_secret_post) 的客户端身份验证是开箱即用的,不需要定制就可以启用它。默认实现由DefaultOAuth2TokenRequestHeadersConverter提供。
JWT Bearer 客户端身份验证的默认实现类是NimbusJwtClientAuthenticationParametersConverter,是在client_assertion参数中添加签名的Token。
NimbusJwtClientAuthenticationParametersConverter生成的JWT默认包含iss、sub、aud、jti、iat和exp声明。可以通过NimbusJwtClientAuthenticationParameter 的setJwtClientAssertionCustomizer() 方法添加定制的headers和claims
oauth2 Client提供了许多自定义OAuth 2.0 Login的配置选项。主要配置选项被分组到它们对应的协议端点中
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.oauth2Login(oauth2 -> oauth2
.authorizationEndpoint(authorization -> authorization
...
)
.redirectionEndpoint(redirection -> redirection
...
)
.tokenEndpoint(token -> token
...
)
.userInfoEndpoint(userInfo -> userInfo
...
)
);
return http.build();
}
}
spring boot OAuth2 支持多种授权方式,Client Credentials,Password Credentials 等,相对Authorization Code Grant 流程简单一些。
OAuth2 Resource Server
在resource Server 上的身份验证(Authentication)基本上与Spring Security身份验证机制一样。
- 过虑器丛web请求中读取Bearer Token并创建BearerTokenAuthenticationToken,然后传递到身份验证管理器(AuthenticationManager)
- 身份验证管理器调用身份验证者(JwtAuthenticationProvider)
- 身份验证者使用使用JwtDecoder对Jwt进行解码、验证和验证,并使用JwtAuthenticationProvider使用JwtAuthenticationConverter将Jwt转换为授予权限(Authority)的集合
- 如果身份验证通过,返回JwtAuthenticationToken,如果失败走异常处理调用AuthenticationEntryPoint
JwtDecoder
在resource Server JwtDecoder 是验证token的关键,有很多相关的配置:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://idp.example.com
jws-algorithms: RS512
jwk-set-uri: https://idp.example.com/.well-known/jwks.json
audiences: https://my-resource-server.example.com
issuer-uri:指定授权服务器,使用默认值,需要的最少配置,其它可以不配置
jwk-set-uri:指定jwk的位置
audiences:默认会验证token payload 中的iss 是否与issuer-uri相同,这个属性还验证aud 是否与audiences值相同
spring:
security:
oauth2:
resourceserver:
jwt:
public-key-location: classpath:my-key.pub
public-key-location:指定非对称加密公钥
Authorization Server
OAuth2AuthorizationServerConfiguration是一个@Configuration,它为OAuth2授权服务器提供最小的默认配置。可以自定义安全配置。
提供了如下的配置选项
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer();
http.apply(authorizationServerConfigurer);
authorizationServerConfigurer
.registeredClientRepository(registeredClientRepository)
.authorizationService(authorizationService)
.authorizationConsentService(authorizationConsentService)
.authorizationServerSettings(authorizationServerSettings)
.tokenGenerator(tokenGenerator)
.clientAuthentication(clientAuthentication -> { })
.authorizationEndpoint(authorizationEndpoint -> { })
.deviceAuthorizationEndpoint(deviceAuthorizationEndpoint -> { })
.deviceVerificationEndpoint(deviceVerificationEndpoint -> { })
.tokenEndpoint(tokenEndpoint -> { })
.tokenIntrospectionEndpoint(tokenIntrospectionEndpoint -> { })
.tokenRevocationEndpoint(tokenRevocationEndpoint -> { })
.authorizationServerMetadataEndpoint(authorizationServerMetadataEndpoint -> { })
.oidc(oidc -> oidc
.providerConfigurationEndpoint(providerConfigurationEndpoint -> { })
.logoutEndpoint(logoutEndpoint -> { })
.userInfoEndpoint(userInfoEndpoint -> { })
.clientRegistrationEndpoint(clientRegistrationEndpoint -> { })
);
return http.build();
}
AuthorizationServerSettings:它指定了协议端点的URI以及颁发者标识符。协议端点的默认URI如下:
public final class AuthorizationServerSettings extends AbstractSettings {
...
public static Builder builder() {
return new Builder()
.authorizationEndpoint("/oauth2/authorize")
.deviceAuthorizationEndpoint("/oauth2/device_authorization")
.deviceVerificationEndpoint("/oauth2/device_verification")
.tokenEndpoint("/oauth2/token")
.tokenIntrospectionEndpoint("/oauth2/introspect")
.tokenRevocationEndpoint("/oauth2/revoke")
.jwkSetEndpoint("/oauth2/jwks")
.oidcLogoutEndpoint("/connect/logout")
.oidcUserInfoEndpoint("/userinfo")
.oidcClientRegistrationEndpoint("/connect/register");
}
...
}
OAuth2ClientAuthenticationConfigurer:通过配置OAuth2ClientAuthenticationFilter, 提供了自定义OAuth2客户端身份验证的功能。
OAuth2ClientAuthenticationFilter是处理客户端身份验证请求的Filter
JwtClientAssertionDecoderFactory:提供一个OAuth2TokenValidator<Jwt>用于用来验证Jwt
claims,通过向setJwtValidatorFactory()提供自定义Function<RegisteredClient, OAuth2TokenValidator<Jwt>>,覆盖默认验证Jwt
claims能力
X509ClientCertificateAuthenticationProviderv:OAuth2客户端身份验证期间使用ClientAuthenticationMethod.TLS_CLIENT_AUTH or ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH 方法时用于验证客户端x509证书链。它还由“证书验证器”组成,用于在TLS握手成功完成后验证客户端x509证书的内容。
RegisteredClient:是向授权服务器注册的客户端。客户端必须先向授权服务器注册,然后才能启动授权授予流(如authorization_code或client_credentials),在客户端注册期间,客户端被分配一个唯一的客户端标识符(clientId),(可选地)一个客户端秘密(clientSecret)(取决于客户端类型),以及与其唯一客户端标识符相关联的元数据。客户机的元数据可以是面向人的显示字符串(如客户机名称),也可以是特定于协议流的项(如有效重定向uri列表)。
RegisteredClientRepository:用于存储RegisteredClient,RegisteredClientRepository提供的实现是InMemoryRegisteredClientRepository和jdbcreregisteredclientrepository。
OAuth2Authorization:OAuth2Authorization是OAuth2授权的表示形式,它保存与资源所有者授予客户端的授权相关的状态,根据不同的授权类型包含不同的OAuth2Token的实现类
OAuth2AuthorizationService:用于存储OAuth2Authorization,OAuth2AuthorizationService提供的实现是InMemoryOAuth2AuthorizationService 和JdbcOAuth2AuthorizationService。
OAuth2AuthorizationConsent:是来自OAuth2授权请求流的授权“同意”(决策)的表示形式——例如,authorization_code授予,它保存资源所有者授予客户端的权限。
OAuth2AuthorizationConsentService:用于存储OAuth2AuthorizationConsent,OAuth2AuthorizationConsentService提供的实现是InMemoryOAuth2AuthorizationConsentService 和JdbcOAuth2AuthorizationConsentService
OAuth2TokenContext:是一个context对象,它包含与OAuth2Token相关的信息,并由OAuth2TokenGenerator和OAuth2TokenCustomizer使用
OAuth2TokenGenerator:负责从提供的OAuth2TokenContext中包含的信息生成OAuth2Token。
OAuth2TokenCustomizer:OAuth2TokenCustomizer提供了自定义OAuth2Token属性的能力,OAuth2TokenGenerator使用它生成OAuth2Token自定义其属性。
SessionRegistry:如果启用OpenID Connect 1.0,则使用SessionRegistry实例跟踪经过验证的会话。OAuth2授权端点关联的SessionAuthenticationStrategy的默认实现类使用SessionRegistry 跟踪身份验证的会话。SessionRegistryImpl 是其默认实现类