Skip to content

Commit

Permalink
✨ Add spring-boot-demo-oauth-authorization-server.
Browse files Browse the repository at this point in the history
  • Loading branch information
lizhongyue248 committed Jan 7, 2020
1 parent 0378ad0 commit dcfeb4f
Show file tree
Hide file tree
Showing 48 changed files with 2,256 additions and 23 deletions.
14 changes: 14 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@
<user.agent.version>1.20</user.agent.version>
</properties>

<repositories>
<repository>
<id>aliyun</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

<dependencyManagement>
<dependencies>
<dependency>
Expand Down
52 changes: 51 additions & 1 deletion spring-boot-demo-oauth/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@

<artifactId>spring-boot-demo-oauth</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<modules>
<module>spring-boot-demo-oauth-authorization-server</module>
</modules>
<packaging>pom</packaging>

<name>spring-boot-demo-oauth</name>
<description>Demo project for Spring Boot</description>
Expand All @@ -28,10 +31,49 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>${spring.boot.version}</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
Expand All @@ -44,6 +86,14 @@
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
= spring-boot-demo-oauth-authorization-server
Doc Writer <lzy@echocow.cn>
v1.0, 2019-01-07
:toc:

spring boot oauth2 授权服务器,

- 授权码模式、密码模式、刷新令牌
- 自定义 UserDetailService
- 自定义 ClientDetailService
- jwt 非对称加密
- 自定义登录授权页面
> SQL 语句
>
> - DDL: `src/test/resources/schema.sql`
> - DML: `src/test/resources/import.sql`

测试用例使用 h2 数据库,测试数据如下:

.测试客户端
|===
|客户端 id |客户端密钥 |资源服务器名称 |授权类型 | scopes| 回调地址

|oauth2
|oauth2
|oauth2
|authorization_code,password,refresh_token
|READ,WRITE
|http://example.com

|test
|oauth2
|oauth2
|authorization_code,password,refresh_token
|READ
|http://example.com


|error
|oauth2
|test
|authorization_code,password,refresh_token
|READ
|http://example.com
|===

.测试用户
|===
|用户名 |密码 |角色

|admin
|123456
|ROLE_ADMIN

|test
|123456
|ROLE_TEST

|===

== 授权码模式

> 测试用例:`com.xkcoding.oauth.oauth.AuthorizationCodeGrantTests`

=== 获取授权码

- 请求地址: http://localhost:8080/oauth/authorize?response_type=code&client_id=oauth2&redirect_uri=http://example.com&scope=READ
- 用户名:admin
- 密码:123456

image::image/Login.png[login]

=== 确认授权

登录成功以后,进入确认授权页面。已经确认过的用户,不会再次要求确认。

image::image/Confirm.png[confirm]

确认授权后,获取授权码

image::image/Code.png[code]

=== 请求 token

使用以下代码可以直接请求 token

[shell]
----
curl --location --request POST 'http://127.0.0.1:8080/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic b2F1dGgyOm9hdXRoMg==' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=GgX6QD' \
--data-urlencode 'redirect_uri=http://example.com' \
--data-urlencode 'client_id=oauth2' \
--data-urlencode 'scope=READ WRITE'
----

得到 token

[token]
----
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyIl0sInVzZXJfbmFtZSI6ImFkbWluIiwic2NvcGUiOlsiUkVBRCJdLCJleHAiOjE1NzgzODY4MTYsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiZjAyMDhiNTUtYTJjYS00NjI4LTg5YjEtNzI5MzY4MzAxOWNhIiwiY2xpZW50X2lkIjoib2F1dGgyIn0.RqJpsin6bMnwI57cGpODTplLeW_gtNWHo_l4SimyRLsnxpCWm5oY1EOb4qVHpXvCbhNsUj69D462P7le13OOmexysZIQhaoGZ_CbIlEp63XsCnr5nSKeX3dgQlyTUDjOUL0WUtY2lKqLCGMeX_rpVhfmSh3b7MC0Ntxq5ao-943QMXGRIeRvJgSkvfY2HBN6-zx1H6rE0wxnUfBC1M08kUkFYlSmsFchiz-E_oTzJvE2D8lA9g-eEFU6cZ_els4Q77Vvc_O6SXUZ7o65vFyLyUjLvh9QF1825SGIUUdXTUYSZjnSAXChhRIAT5pLRHK-gthIzpOaWrgj6ebUoG02Eg",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyIl0sInVzZXJfbmFtZSI6ImFkbWluIiwic2NvcGUiOlsiUkVBRCJdLCJhdGkiOiJmMDIwOGI1NS1hMmNhLTQ2MjgtODliMS03MjkzNjgzMDE5Y2EiLCJleHAiOjE1NzgzODY4MTYsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiMGViNTU2MTQtYjgxYS00MTFmLTg1MTAtZThkMjZmODJmMjJhIiwiY2xpZW50X2lkIjoib2F1dGgyIn0.CBGcjirkf-3187SgbZr0ikauiCS8U9YLaoR4sNlRQjd-gaIeF5PChnIs_yAmG_VpqPFlPRdSl8DA05S2QnFpT3TkRjyP-LPDZgsVAPfczMAdVywU1zOKYZeq-gM6p9bmGEabbZoBlIxOImsjeyFSCui6UtRTZjNlj3AhGIzvs52T8bDqC796iHPDZvJ97MMgsEiRyu-mxDm1o1LMuBX9RHCx9rAkBVf52q36bqWMcYAlDOu1wYjpmhalSLZyWcmraQvClEitXGJI4eTFapTnuXQuWFIL-973V_5Shw98-bk65zZQOEheazHrUf-n4h-sYT4akehnYSVxX2UIg9XsCw",
"expires_in": 5999,
"scope": "READ",
"jti": "f0208b55-a2ca-4628-89b1-7293683019ca"
}
----

== 密码模式

> 测试用例:`com.xkcoding.oauth.oauth.ResourceOwnerPasswordGrantTests`

`test` 用户进行授权

[source]
----
curl --location --request POST 'http://127.0.0.1:8080/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic b2F1dGgyOm9hdXRoMg==' \
--data-urlencode 'password=123456' \
--data-urlencode 'username=test' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'scope=READ WRITE'
----

== 刷新令牌

携带 `refresh_token` 去请求

[source]
----
curl --location --request POST 'http://127.0.0.1:8080/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic b2F1dGgyOm9hdXRoMg==' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyIl0sInVzZXJfbmFtZSI6ImFkbWluIiwic2NvcGUiOlsiUkVBRCJdLCJhdGkiOiJmMDIwOGI1NS1hMmNhLTQ2MjgtODliMS03MjkzNjgzMDE5Y2EiLCJleHAiOjE1NzgzODY4MTYsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiMGViNTU2MTQtYjgxYS00MTFmLTg1MTAtZThkMjZmODJmMjJhIiwiY2xpZW50X2lkIjoib2F1dGgyIn0.CBGcjirkf-3187SgbZr0ikauiCS8U9YLaoR4sNlRQjd-gaIeF5PChnIs_yAmG_VpqPFlPRdSl8DA05S2QnFpT3TkRjyP-LPDZgsVAPfczMAdVywU1zOKYZeq-gM6p9bmGEabbZoBlIxOImsjeyFSCui6UtRTZjNlj3AhGIzvs52T8bDqC796iHPDZvJ97MMgsEiRyu-mxDm1o1LMuBX9RHCx9rAkBVf52q36bqWMcYAlDOu1wYjpmhalSLZyWcmraQvClEitXGJI4eTFapTnuXQuWFIL-973V_5Shw98-bk65zZQOEheazHrUf-n4h-sYT4akehnYSVxX2UIg9XsCw'
----

== 解析令牌

携带令牌解析

[source]
----
curl --location --request POST 'http://127.0.0.1:8080/oauth/check_token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic b2F1dGgyOm9hdXRoMg==' \
--data-urlencode 'token='
----

解析结果

[source]
----
{
"aud": [
"oauth2"
],
"user_name": "admin",
"scope": [
"READ",
"WRITE"
],
"active": true,
"exp": 1578389936,
"authorities": [
"ROLE_ADMIN"
],
"jti": "fe59fce9-6764-435e-8fa7-7320e11af811",
"client_id": "oauth2"
}
----

== 退出登录

授权码模式登陆是在授权服务器上登录的,所以退出也要在授权服务器上退出。

携带回调地址进行退出,退出完成后跳转到回调地址:

image::image/Logout.png[logout]

退出以后自动跳转到回调地址(要加 `http` 或 `https`)

== 获取公钥

通过访问 '/oauth/token_key' 获取 JWT 公钥

[source]
----
curl --location --request GET 'http://127.0.0.1:8080/oauth/token_key' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic b2F1dGgyOm9hdXRoMg=='
----

获取后

[source]
----
{
"alg": "SHA256withRSA",
"value": "-----BEGIN PUBLIC KEY-----\n......\n-----END PUBLIC KEY-----"
}
----

== 核心配置

=== 授权服务器配置

[Oauth2AuthorizationServerConfig]
----
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
// 自定义用户
.userDetailsService(sysUserService)
// 内存存储
.tokenStore(tokenStore)
// jwt 令牌转换
.accessTokenConverter(jwtAccessTokenConverter);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 从数据库读取我们自定义的客户端信息
clients.withClientDetails(sysClientDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security
// 获取 token key 需要进行 basic 认证客户端信息
.tokenKeyAccess("isAuthenticated()")
// 获取 token 信息同样需要 basic 认证客户端信息
.checkTokenAccess("isAuthenticated()");
}
----

=== 安全配置

[WebSecurityConfig]
----
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 开启表单登录,授权码模式的时候进行登录
.formLogin()
// 路径等
.loginPage("/oauth/login")
.loginProcessingUrl("/authorization/form")
// 失败以后携带错误信息进行再次跳转登录页面
.failureHandler(clientLoginFailureHandler)
.and()
// 退出登录相关
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(clientLogoutSuccessHandler)
.and()
// 授权服务器安全配置
.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.anyRequest()
.authenticated();
}
----

== 参考

- https://echocow.cn/articles/2019/07/14/1563096109754.html[Spring Security Oauth2 从零到一完整实践(三)授权服务器 ]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-boot-demo-oauth</artifactId>
<groupId>com.xkcoding</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-boot-demo-oauth-authorization-server</artifactId>


</project>
Loading

0 comments on commit dcfeb4f

Please sign in to comment.