# spring oauth2
**Repository Path**: 1111pp/oauth2
## Basic Information
- **Project Name**: spring oauth2
- **Description**: spring security5.x
spring-security-oauth2-client 客户端支持
spring-security-oauth2-resource-server 资源服务器
spring-security-oauth2-authorization-server 最新版本 授权服务器
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: dev
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 4
- **Created**: 2022-07-26
- **Last Updated**: 2022-07-26
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# spring oauth2
## 版本
2018 年初,我们[宣布](https://spring.io/blog/2018/01/30/next-generation-oauth-2-0-support-with-spring-security)Spring Security OAuth 项目正式进入维护模式。我们已经停止支持 2.0.x,与 Boot 的 1.x End-of-Life (EOL) 以及 2.1.x 和 2.2.x 一致。我们的计划是在不久的将来停止剩余的支持。
当前支持的分支是 2.3.x 和 2.4.x。2.3.x 系列将于 2020 年 3 月停产。我们将在达到功能对等后至少一年支持 2.4.x 系列。
为此,随着 Spring Security 5.2 的发布,我们强烈鼓励用户[开始将其遗留的 OAuth 2.0 客户端和资源服务器](https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Migration-Guide)应用程序[迁移](https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Migration-Guide)到 Spring Security 5.2 中的新支持。
spring-security 5.2.x 并不能完全替代以上的项目提供的功能,只是将上面中部分主要的功能先集成进来
预计在未来 spring-security 5.3.x(5.3第一个版本大约在2020.3) 之后的版本,将可以只使用 spring-security,不需要在学习以上的其他的部分
```java
原因是Oauth2 落地混乱:Spring Security OAuth、Spring Cloud Security、Spring Boot 1.5.x 以及当时最新的 Spring Security5.x 中都提供了对 OAuth2 的实现。因此官方要统一放在一个地方。
```
```java
在 `Spring Security 5`中,现在已经不提供了 `授权服务器` 的配置,但是 **授权服务器** 在我们平时的开发过程中用的还是比较多的。不过 Spring 官方提供了一个 由Spring官方主导,社区驱动的授权服务 `spring-authorization-server`,目前已经到了 0.1.2 的版本,不过该项目还是一个实验性的项目,不可在生产环境中使用,此处来使用项目搭建一个简单的授权服务器。
```
**springcloud 版本**
```xml
org.springframework.cloud
spring-cloud-starter-oauth2
2.2.4.RELEASE
```
**springboot 版本**
```xml
org.springframework.security.oauth
spring-security-oauth2
2.5.0.RELEASE
```
**springsecurity5**
```xml
org.springframework.security
spring-security-oauth2-core
5.5.0
org.springframework.security
spring-security-oauth2-client
org.springframework.security
spring-security-oauth2-resource-server
```
**最新版本 授权服务器**
实验项目2020-8月--2021-7月
```xml
org.springframework.security.experimental
spring-security-oauth2-authorization-server
0.1.2
```
正式项目 2021-8月 开始
```xml
org.springframework.security
spring-security-oauth2-authorization-server
0.2.1
```
结论:
- 优先选择 Spring 官方推荐的 spring security 5.2.x +
- 在 spring security5.3.x 前可以选择使用 `spring-security-oauth`(未来终将被 spring security5.x取代)
- 不要再使用 `spring-security-xxx`、`spring-social`等
- 不推荐使用 `spring-cloud-starter-oauth2`、`spring-cloud-starter-security`(有计划被废弃)
**spring-security-oauth2 版本的教程网上有很多,这里不多赘述,但是已经不推荐使用**
**个人觉得原因**
- 流程不够标准
- 组件不够清
- 安全性不如新版本
接下来分析 spring security 包下Oauth2
1. **spring-security-oauth2-client 客户端**
2. **spring-security-oauth2-resource-server 资源服务器**
3. **spring-security-oauth2-authorization-server 授权服务器(spring 妥协用户开发的新版授权服务器)**
4. **spring-security-oauth2-jose Javascript 对象签名和加密(包括jwt kws jwe jwk)**
## 授权模式
- OAuth2有4种授权模式:1授权码模式 2简化模式 3密码模式 4客户端模式(在 2.1版本 密码模式和简化模式被移除)
- OAuth2分为3个部分:1认证服务器 2资源服务器 3第三方应用
| **GRANT_TYPE** | **Description** | 备注 |
| :----------------- | ------------------------------------------------------------ | ---- |
| authorization_code | 授权码模式(即先登录获取code,再获取token) [最常用] | |
| password | 密码模式(将用户名、密码传过去,直接获取token) [适用于移动设备] | |
| client_credentials | 客户端模式(无用户,用户向客户端注册,然后客户端以自己的名义向'服务端'获取资源) | |
| implicit | 简化模式(在redirect_uri的Hash传递token,客户端运行在浏览器中,如JS、Flash) | |
| refresh_token | 更新access_token | |
### 端点 endpoint
**/oauth2/authorize 获取授权码**
```xml
http://localhost:9000/oauth2/authorize?response_type=code&client_id=cilentId&scope=read&redirect_uri=http://www.baidu.com&state=state
```
**/oauth2/token 获取access_token. 需要 http basic 加密**
```xml
"Authorization: Basic Y2lsZW50SWQxOnNlY3JldDE="
http://localhost:9000/oauth2/token?grant_type=authorization_code&code=38YHBf-KWEkWV1gR6PSYhc2fYtQF5IhRY--uZnj2gQnJvK0vUl2b7dx6mCXRjNEFZgU2-SLn3yZf-FmeJiE8XSBJOYMOnw7uOA2qn9b7ebIVFn6ttDtUlp0IXSCBQ-T3&redirect_uri=http://www.baidu.com
```
**请求资源 需要 http basic 加密**
```xml
"Authorization: Bearer eyJraWQiOiJkNjE3MzFkYy1kMmMzLTQ4MzItYTI4NC1lNGVlMWRlNzdlOGIiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxODA5MTY4MTgwNCIsImF1ZCI6ImNpbGVudElkMSIsIm5iZiI6MTY0MDY5MzMyNiwic2NvcGUiOlsicmVhZCJdLCJpc3MiOiJodHRwOlwvXC8xMjcuMC4wLjE6OTAwMCIsImV4cCI6MTY0MDY5MzYyNiwiaWF0IjoxNjQwNjkzMzI2fQ.bp58GZqd7nNTqSFuQoxLkj9kbvQnBzzYjXEKflxzk6gH71tRsGOYUJ34ypFXA1fALP1FPJyr-X3jtGfbm3vaV3zVu0rV_FFNBNS6b6d7vGAQl4gc6r5PtMzZkh8YoszabuDN2CFiM6ViVZri_c6yo0AEZfoVkegoDzk0EMPJiJxWA1pLQtz42Eo987Pg8ds8yz5UISnKsfJT29ai49oXeiUOSxJKxqq5Bml0tKEOjiBoAkKM06jhfWf_qJeVyKDNTb9cWT3wfQ1_gHeLsnH2uabJQimWSQFUQO0Lp8Akiwame3mGzhWV9btfMdBdsdKIAdEaAjNqcM0FLfgCwi0ifA"
http://localhost:8000/api/getResource
```
### spring-security-oauth2-client
**spring-security-oauth2-client 客户端 支持openid connect 1.0 协议**
ClientRegistrationRepository 是客户端 三方登录的 元信息
可以外部化配置
```java
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
// registerId 指定服务的名称 一般github 为github
ClientRegistration clientRegistration = ClientRegistration.withRegistrationId("registerId")
.clientId("cilentId")//三方服务分配的一个cilentId
.clientSecret("secret")//三方服务分配的一个secret
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)//(4) 服务端支持的认证方式
.clientName("clientName")//随便写
.tokenUri("http://127.0.0.1:9000/oauth2/token")
.authorizationUri("http://127.0.0.1:9000/oauth2/authorize")
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.scope("openid") // (10)
.userNameAttributeName("username") // (11)
.userInfoUri("http://127.0.0.1:9000/getUser")
.redirectUri("http://127.0.0.1:9001/login/oauth2/code/registerId")
.jwkSetUri("") // (13)
.build();
return new InMemoryClientRegistrationRepository(clientRegistration);
}
```
**核心过滤器**
```java
OAuth2AuthorizationRequestRedirectFilter oauth授权请求重定向过滤器 默认uri "/oauth2/authorization"
OAuth2AuthorizationCodeGrantFilter OAuth2 授权码授予过滤器
OAuth2LoginAuthenticationFilter OAuth2 登录认证过滤器
```
**自动装配 org.springframework.boot.autoconfigure.security.oauth2.client.servlet. 包下,类**
```java
OAuth2ClientAutoConfiguration 配置入口
OAuth2ClientRegistrationRepositoryConfiguration 三方授权服务器相关配置
OAuth2WebSecurityConfiguration web配置
```
**首先获取配置的选项 有没有公共三方配置,目前支持 GITHUB, GOOGLE,OKTA**
```java
public enum CommonOAuth2Provider {
GOOGLE {
public Builder getBuilder(String registrationId) {
Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
builder.scope(new String[]{"openid", "profile", "email"});
builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth");
builder.tokenUri("https://www.googleapis.com/oauth2/v4/token");
builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs");
builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
builder.userNameAttributeName("sub");
builder.clientName("Google");
return builder;
}
},
GITHUB {
public Builder getBuilder(String registrationId) {
Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
builder.scope(new String[]{"read:user"});
builder.authorizationUri("https://github.com/login/oauth/authorize");
builder.tokenUri("https://github.com/login/oauth/access_token");
builder.userInfoUri("https://api.github.com/user");
builder.userNameAttributeName("id");
builder.clientName("GitHub");
return builder;
}
},
........
```
**核心 处理器**
```java
OAuth2LoginAuthenticationProvider
```
### spring-security-oauth2-resource-server 资源服务器
资源服务器的 核心配置是在core 包, 资源服务器 使核心过滤器拦截 jwt 的token 并且解析 认证
自动装配
```
OAuth2ResourceServerAutoConfiguration
```
过滤器配置
```java
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.mvcMatchers("/getUser")
// oauth2 权限是以 SCOPE_ 开头
.access("hasAuthority('SCOPE_read')")
.and()
.oauth2ResourceServer()
.jwt();
DefaultSecurityFilterChain build = http.build();
return build;
}
```
核心过滤器,如果请求头包含bearerToken 则拦截
```java
BearerTokenAuthenticationFilter
```
```java
bearerTokenString token;
try {
// 获取bearerToken
token = this.bearerTokenResolver.resolve(request);
}
catch (OAuth2AuthenticationException invalid) {
this.logger.trace("Sending to authentication entry point since failed to resolve bearer token", invalid);
this.authenticationEntryPoint.commence(request, response, invalid);
return;
}
if (token == null) {
this.logger.trace("Did not process request since did not find bearer token");
filterChain.doFilter(request, response);
return;
}
```
核心处理器 能根据jwt算法和加密参数 正常解析 bearerToken则 认证通过
```
JwtAuthenticationProvider
```
```java
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
BearerTokenAuthenticationToken bearer = (BearerTokenAuthenticationToken) authentication;
Jwt jwt = getJwt(bearer);
// 解析jwt 加密数据
AbstractAuthenticationToken token = this.jwtAuthenticationConverter.convert(jwt);
token.setDetails(bearer.getDetails());
this.logger.debug("Authenticated token");
return token;
}
```
### spring-security-oauth2-authorization-server
新版授权服务器
###
获取code 端点 DEFAULT_AUTHORIZATION_ENDPOINT_URI = "/oauth2/authorize";
```
OAuth2AuthorizationEndpointFilter
```
处理器
```java
class OAuth2AuthorizationCodeRequestAuthenticationProvider{
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
OAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication =
(OAuth2AuthorizationCodeRequestAuthenticationToken) authentication;
//isConsent() 是否授权同意
return authorizationCodeRequestAuthentication.isConsent() ?
authenticateAuthorizationConsent(authentication) :
authenticateAuthorizationRequest(authentication);
}
}
```
获取token 端点DEFAULT_TOKEN_ENDPOINT_URI = "/oauth2/token";
过滤器
```
OAuth2ClientAuthenticationFilter // 校验 cilent_id 和serct
OAuth2TokenEndpointFilter //校验code
```
处理器
```
OAuth2ClientAuthenticationProvider
OAuth2AuthorizationCodeAuthenticationProvider
```