OAuth2 授权码模式模式基本上是用用户凭证获取token 后来获取资源的访问权限。其交互步骤如下图:
交互过程如下:
- 用户在客户端程序上操作某些功能希望从资源服务器获取数据
- 客户端程序重定向浏览器请求到授权服务器要求授权,在重定向之前客户端程序会给授权服务器传递一个参数作为回调地址
- 授权服务器请求用户同意,这个步骤一般需要用户先登录,如果已经登录则可能弹出一个交互页面请求用户同意授权
- 用户决定同意授权
- 授权服务器重定向到第二步的回调地址,并且在URL 后附带一个Authorization Code,这个Authorization Code 是明文传递给客户端程序的,所以不安全
- 客户端程序用 Authorization Code 和 认证的密钥获取 access token
- 客户端程序用access token 访问资源服务器(也就是实际的业务接口)
- 资源服务器返回数据给客户端程序
交互图如下
Spring Authorization Server 是一个spring 专门处理授权服务的项目,我们构建授权服务器就是基于它。 我们先一步一步操作完成后再看整个流程。
2.1 建立基本项目结构整体项目结构如下
创建一个maven 项目oauth2-auth-server
pom.xml 如下:
源码地址 :细节请参考项目源码
4.0.0 org.springframework.boot spring-boot-starter-parent 2.6.7 com.xue oauth2-auth-server 2022.04.28 oauth2-auth-server spring Authorization Server Demo project for Spring Boot 17 3.9.1 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-jpa org.springframework.security spring-security-oauth2-authorization-server 0.2.3 p6spy p6spy ${p6spy} com.h2database h2 runtime mysql mysql-connector-java runtime org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-devtools runtime true org.springframework.boot spring-boot-maven-plugin
注意 spring-security-oauth2-authorization-server这个依赖是最重要的
项目的配置文件application.yml如下
源码地址 :[细节请参考项目源码]
#https://docs.spring.io/spring-boot/docs spring文档
# https://docs.spring.io/spring-boot/docs/2.6.3/reference/html/application-properties.html#application-properties
server:
port: 9000
# 默认激活dev配置
spring:
profiles:
active: "dev"
#active: "prod"
group:
"dev": "common,jpa,h2,dev"
"prod": "common,jpa,mysql,prod"
---
spring:
config:
activate:
on-profile: "mysql"
jdbc:
database: mysql
init-mode: ALWAYS
driver-class-name: com.mysql.cj.jdbc.Driver
---
spring:
config:
activate:
on-profile: "h2"
h2:
console:
#数据库控制台 http://localhost:9000/h2-console/login.jsp
path: /h2-console
enabled: true
setting:
web-allow-others: true
jdbc:
database: h2
init-mode: EMBEDDED
driver-class-name: org.h2.Driver
---
spring:
config:
activate:
on-profile: "dev"
jdbc:
#是否打印sql,true 或false
show-sql: true
url: mem:db1;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;TRACE_LEVEL_SYSTEM_OUT=2
username: test
password:
---
spring:
config:
activate:
on-profile: "prod"
devtools:
restart:
enabled : false
jdbc:
#是否打印sql,true 或false
show-sql: false
url: //localhost:8024/test?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8
username: test
password: 123456
---
spring:
config:
activate:
on-profile: "common"
application:
name: auth-server
logging:
path : ./
datasource:
driver-class-name: ${jdbc.driver-class-name-show-sql-${jdbc.show-sql}}
url : ${jdbc.url-show-sql${jdbc.show-sql}}
username: ${jdbc.username}
password: ${jdbc.password}
#连接池池参数配置
type: com.zaxxer.hikari.HikariDataSource
hikari:
pool-name: hikariDataSourcePool
connection-test-query: SELECT 1
#connection-test-query: SELECT 1
maximum-pool-size: 20
minimum-idle: 5
#默认30000 30s
connection-timeout: 10000
#默认5000
validation-timeout: 3000
#默认true
is-auto-commit: false
#默认false
is-read-only: false
jdbc:
#不打印sql
driver-class-name-show-sql-false: ${jdbc.driver-class-name}
url-show-sql-false : jdbc:${jdbc.database}:${jdbc.url}
#打印sql
driver-class-name-show-sql-true : com.p6spy.engine.spy.P6SpyDriver
url-show-sql-true : jdbc:p6spy:${jdbc.database}:${jdbc.url}
---
spring:
config:
activate:
on-profile: "jpa"
jpa:
database: ${jdbc.database}
show-sql: false
hibernate:
ddl-auto: update
open-in-view: false
注意我们的服务运行在 9000 端口
我们把用户信息用JPA 保存到数据库中,所以先建立用户模型
User.java
package com.xue.pojo;
@Entity
@Table(name = "sys_user")
public class User implements UserDetails {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private final String username;
private final String password;
private final String role;
... 代码太多请参考项目源码
}
UserRepository.java 用户DAO 层
public interface UserRepository extends CrudRepository{ User findByUsername(String username); }
SecurityConfig.java spring安全配置
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
// @formatter:off
return http
//设置了
其他代码请参考
项目源码地址
如果一切没问题的话,现在可以来一个全流程的测试
-
启动授权服务器 oauth2-auth-server
-
启动资源服务器oauth2-res-server
-
启动客户端 oauth2-client-app
-
我们现在就是用户 访问 oauth2-client-app 程序 在浏览器中输入 http://localhost:9090/ 访问
-
如果你已经登录会直接看到第6步的页面,由于我们没有登录 被拦截后重定向到认证服务器 页面,如下图
-
输入a1,密码 1 进入授权页面
-
点击同意授权程序重定向到
-
点击原材料管理,发现现在客户端可以访问资源服务器提供的接口



