This commit is contained in:
parent
12a5550688
commit
e9208eb51b
|
|
@ -0,0 +1,190 @@
|
||||||
|
# OAuth2/OIDC 统一认证系统
|
||||||
|
|
||||||
|
这是一个基于Spring Boot的多服务架构,使用OAuth2和OIDC实现统一认证。
|
||||||
|
|
||||||
|
## 系统架构
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│ 前端应用 │ │ 网关服务 │ │ 资源服务 │
|
||||||
|
│ (a.sun.com) │───▶│ (8080) │───▶│ (8081) │
|
||||||
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│ OIDC服务器 │ │ JWT验证 │ │ 受保护资源 │
|
||||||
|
│ (9000) │ │ Token转发 │ │ API端点 │
|
||||||
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 服务组件
|
||||||
|
|
||||||
|
### 1. OIDC授权服务器 (oidc/)
|
||||||
|
- **端口**: 9000
|
||||||
|
- **功能**: OAuth2/OIDC授权服务器
|
||||||
|
- **客户端配置**:
|
||||||
|
- 客户端ID: `a-client`
|
||||||
|
- 客户端密钥: `a-secret`
|
||||||
|
- 重定向URI: `http://a.sun.com/callback`
|
||||||
|
- 授权类型: `authorization_code`, `refresh_token`
|
||||||
|
- 作用域: `openid`, `read`
|
||||||
|
|
||||||
|
### 2. 网关服务 (gateway/)
|
||||||
|
- **端口**: 8080
|
||||||
|
- **功能**: API网关,JWT验证,Token转发
|
||||||
|
- **特性**:
|
||||||
|
- JWT Token验证
|
||||||
|
- 路由转发到后端服务
|
||||||
|
- Token Relay功能
|
||||||
|
|
||||||
|
### 3. 资源服务 (resourceservice/)
|
||||||
|
- **端口**: 8081
|
||||||
|
- **功能**: 后端API服务
|
||||||
|
- **端点**: `/api/resource` (GET)
|
||||||
|
|
||||||
|
### 4. 前端应用 (resourceservicehtml/)
|
||||||
|
- **域名**: a.sun.com
|
||||||
|
- **功能**: 用户界面,OIDC登录流程
|
||||||
|
- **页面**:
|
||||||
|
- `index.html`: 主页面,包含登录和API调用功能
|
||||||
|
- `callback.html`: OIDC回调处理页面
|
||||||
|
- `test.html`: 配置测试页面
|
||||||
|
|
||||||
|
## 认证流程
|
||||||
|
|
||||||
|
### 1. 用户登录流程
|
||||||
|
1. 用户访问 `http://a.sun.com`
|
||||||
|
2. 前端检查本地Token
|
||||||
|
3. 如果没有Token,重定向到OIDC登录页面
|
||||||
|
4. 用户在OIDC服务器登录
|
||||||
|
5. OIDC服务器重定向回 `http://a.sun.com/callback`
|
||||||
|
6. 前端用授权码交换Token
|
||||||
|
7. Token保存到本地存储
|
||||||
|
|
||||||
|
### 2. API调用流程
|
||||||
|
1. 前端使用Token调用 `/api/resource`
|
||||||
|
2. 请求经过nginx代理到网关
|
||||||
|
3. 网关验证JWT Token
|
||||||
|
4. 网关转发请求到资源服务
|
||||||
|
5. 资源服务返回数据
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
### OIDC服务器配置
|
||||||
|
- 使用内存存储用户和客户端
|
||||||
|
- 默认用户: `user/password`
|
||||||
|
- RSA密钥对用于JWT签名
|
||||||
|
|
||||||
|
### 网关配置
|
||||||
|
- WebFlux架构
|
||||||
|
- JWT Token验证
|
||||||
|
- 路由配置指向资源服务
|
||||||
|
|
||||||
|
### 前端配置
|
||||||
|
- OIDC客户端配置
|
||||||
|
- Token本地存储
|
||||||
|
- 状态参数防CSRF攻击
|
||||||
|
|
||||||
|
## 启动顺序
|
||||||
|
|
||||||
|
1. **启动OIDC服务器**:
|
||||||
|
```bash
|
||||||
|
cd oidc
|
||||||
|
mvn spring-boot:run
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **启动网关服务**:
|
||||||
|
```bash
|
||||||
|
cd gateway
|
||||||
|
mvn spring-boot:run
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **启动资源服务**:
|
||||||
|
```bash
|
||||||
|
cd resourceservice
|
||||||
|
mvn spring-boot:run
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **配置nginx**:
|
||||||
|
```bash
|
||||||
|
sudo cp resourceservicehtml/nginx.conf /opt/homebrew/etc/nginx/nginx.conf
|
||||||
|
sudo nginx -s reload
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **配置hosts**:
|
||||||
|
```
|
||||||
|
127.0.0.1 a.sun.com
|
||||||
|
127.0.0.1 oidc.sun.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## 测试
|
||||||
|
|
||||||
|
### 1. 访问前端
|
||||||
|
- 主页: `http://a.sun.com`
|
||||||
|
- 测试页面: `http://a.sun.com/test.html`
|
||||||
|
|
||||||
|
### 2. 测试OIDC端点
|
||||||
|
- JWKS: `http://localhost:9000/oauth2/jwks`
|
||||||
|
- 授权端点: `http://localhost:9000/oauth2/authorize`
|
||||||
|
- Token端点: `http://localhost:9000/oauth2/token`
|
||||||
|
|
||||||
|
### 3. 测试API
|
||||||
|
- 资源API: `http://a.sun.com/api/resource`
|
||||||
|
|
||||||
|
## 安全特性
|
||||||
|
|
||||||
|
- JWT Token验证
|
||||||
|
- 状态参数防CSRF攻击
|
||||||
|
- HTTPS重定向支持
|
||||||
|
- Token过期处理
|
||||||
|
- 刷新Token机制
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
### 常见问题
|
||||||
|
|
||||||
|
1. **OIDC发现端点无法访问**
|
||||||
|
- 检查OIDC服务器是否启动
|
||||||
|
- 验证安全配置
|
||||||
|
|
||||||
|
2. **Token验证失败**
|
||||||
|
- 检查Token是否过期
|
||||||
|
- 验证JWT签名
|
||||||
|
|
||||||
|
3. **nginx权限问题**
|
||||||
|
- 确保nginx用户有读取权限
|
||||||
|
- 检查目录权限设置
|
||||||
|
|
||||||
|
4. **CORS问题**
|
||||||
|
- 检查前端域名配置
|
||||||
|
- 验证重定向URI设置
|
||||||
|
|
||||||
|
## 开发说明
|
||||||
|
|
||||||
|
### 添加新客户端
|
||||||
|
在 `oidc/src/main/java/com/tuoheng/oauth/oidc/config/SecurityConfig.java` 中添加新的 `RegisteredClient`。
|
||||||
|
|
||||||
|
### 添加新API端点
|
||||||
|
在 `resourceservice` 中添加新的Controller和端点。
|
||||||
|
|
||||||
|
### 修改前端配置
|
||||||
|
在 `resourceservicehtml/index.html` 中修改 `oidcConfig` 对象。
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- **后端**: Spring Boot 3.x, Spring Security, Spring Cloud Gateway
|
||||||
|
- **前端**: HTML5, JavaScript, CSS3
|
||||||
|
- **认证**: OAuth2, OpenID Connect, JWT
|
||||||
|
- **代理**: nginx
|
||||||
|
- **构建**: Maven
|
||||||
|
|
||||||
|
## 版本信息
|
||||||
|
|
||||||
|
- Spring Boot: 3.5.3
|
||||||
|
- Spring Security: 6.5.1
|
||||||
|
- Spring Cloud Gateway: 4.1.1
|
||||||
|
- Java: 17
|
||||||
|
|
||||||
|
|
||||||
|
mkcert -uninstall && mkcert -install && mkcert -key-file ssl/private.key -cert-file ssl/certificate.crt "*.local.com" local.com
|
||||||
|
|
@ -5,7 +5,17 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="b713637a-3b19-4c5b-9e88-95e35dd83d2e" name="更改" comment="">
|
<list default="true" id="b713637a-3b19-4c5b-9e88-95e35dd83d2e" name="更改" comment="">
|
||||||
|
<change beforePath="$PROJECT_DIR$/../nginx/nginx.conf" beforeDir="false" afterPath="$PROJECT_DIR$/../nginx/nginx.conf" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/../oidc/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../oidc/pom.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/../oidc/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../oidc/pom.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../oidc/src/main/java/com/tuoheng/oauth/oidc/config/SecurityConfig.java" beforeDir="false" afterPath="$PROJECT_DIR$/../oidc/src/main/java/com/tuoheng/oauth/oidc/config/SecurityConfig.java" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../oidc/src/main/resources/application.properties" beforeDir="false" afterPath="$PROJECT_DIR$/../oidc/src/main/resources/application.properties" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../resourceservice/target/classes/com/tuoheng/resourceservice/HelloController.class" beforeDir="false" afterPath="$PROJECT_DIR$/../resourceservice/target/classes/com/tuoheng/resourceservice/HelloController.class" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../resourceservice/target/classes/com/tuoheng/resourceservice/ResourceServiceApplication.class" beforeDir="false" afterPath="$PROJECT_DIR$/../resourceservice/target/classes/com/tuoheng/resourceservice/ResourceServiceApplication.class" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../resourceservicehtml/callback.html" beforeDir="false" afterPath="$PROJECT_DIR$/../resourceservicehtml/callback.html" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../resourceservicehtml/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/../resourceservicehtml/index.html" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../resourceservicehtml/test.html" beforeDir="false" afterPath="$PROJECT_DIR$/../resourceservicehtml/test.html" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../ssl/certificate.crt" beforeDir="false" afterPath="$PROJECT_DIR$/../ssl/certificate.crt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../ssl/private.key" beforeDir="false" afterPath="$PROJECT_DIR$/../ssl/private.key" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
|
@ -105,7 +115,7 @@
|
||||||
<workItem from="1752741336600" duration="2274000" />
|
<workItem from="1752741336600" duration="2274000" />
|
||||||
<workItem from="1752745264222" duration="2832000" />
|
<workItem from="1752745264222" duration="2832000" />
|
||||||
<workItem from="1752751160098" duration="1320000" />
|
<workItem from="1752751160098" duration="1320000" />
|
||||||
<workItem from="1752798688493" duration="5384000" />
|
<workItem from="1752798688493" duration="8093000" />
|
||||||
</task>
|
</task>
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>OAuth2 登录</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; background: #f5f5f5; }
|
||||||
|
.login-box { width: 300px; margin: 100px auto; background: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 2px 8px #ccc; }
|
||||||
|
.login-box h2 { text-align: center; margin-bottom: 20px; }
|
||||||
|
.login-box input { width: 100%; padding: 8px; margin: 10px 0; border: 1px solid #ddd; border-radius: 4px; }
|
||||||
|
.login-box button { width: 100%; padding: 10px; background: #1976d2; color: #fff; border: none; border-radius: 4px; cursor: pointer; }
|
||||||
|
.login-box button:disabled { background: #aaa; }
|
||||||
|
.msg { color: #d32f2f; text-align: center; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="login-box">
|
||||||
|
<h2>OAuth2 登录</h2>
|
||||||
|
<form method="post" action="/login">
|
||||||
|
<input type="text" name="username" placeholder="用户名" required autocomplete="username">
|
||||||
|
<input type="password" name="password" placeholder="密码" required autocomplete="current-password">
|
||||||
|
<button type="submit">登录</button>
|
||||||
|
</form>
|
||||||
|
<div class="msg"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/FXUfK+ry8hUJ
|
||||||
|
H3mYhlDukXW05kLTRjyMd8G7s8Qt3M9B1e92rxHNKcU45+lSDTF8bb1JF6DzCXmo
|
||||||
|
Clon/6H8YvHzD3RyypmqCRi17qQwch5Jtprtb8lCJVcBClDUFjoeTtPXpJMXdH5P
|
||||||
|
xjLR6Aa3Z4HpBpIKMsvp9ZaAG0XQDTUo8urcIeV16iRsRfqLRufwQ4gVlVxuOJVb
|
||||||
|
mHmKyBJZja+iBVlsiVBggMQJq2a2HQE4Lk2lv+7uWqbJ2MrL8d8aOkJIt+YtqlxV
|
||||||
|
mv2vLoLw2hAd4emnF2ijFEYJtNzepJ5X0nltzAHQd+uW44sTjWlMOopqKpqD1+R9
|
||||||
|
ZNsMsdupAgMBAAECggEAGVETenTMJTITvWixKJcrI+Cb0sLrOajFnurC/UZ9CIKH
|
||||||
|
5zYcCwJ4/lC5c6euTxO2acD0YjnCNlEcEDqG5WPGJ3VIjyaODCNxpoicAIbEtDJ6
|
||||||
|
dtO9xRWZea0O0PF38hGb06YoBRsl7eaeUZ114D+4nBYXrTMUqEtAnxfNv91dK4pJ
|
||||||
|
byV1Wp+bHgXzIH4kM3dPjOsDwAUIgtmUFrSXdsG+OzlTZxUiCShAWFXe9W5KiLR0
|
||||||
|
fZJkCu2qhLg7QQvgrGmp4PRov97dJqbh0XXCyDLHmVbjqrkCD8AcdBqtRI45B2TA
|
||||||
|
STbNcq6nlXf2VOsVjHnDoIEDwpDDeCDesDfnSVPzgQKBgQDE75cWIjH7/DXBJ0rN
|
||||||
|
x81v2MwEZw3zLdq5GNENPitbHRgPZ8jvEsABg5hJButucjyxOPopdYQg+c6QhkMG
|
||||||
|
qumig3k9aOVonVOrF3+iXGoMWjp3yZypS15hJzx1M7WneY1ctE3RQ2tIwOk8xKPB
|
||||||
|
BXSOsbAlVIlUfRqHO9h0m2JTeQKBgQD4ZI3oXAkKAYfGlZRY+FJ+As/p9PhQovv6
|
||||||
|
nq/F1BwF9NvLjihzt71pYVbEcZkkUA2QHxQEMKerVLpRIhaschmnCIyqh8w1wfyj
|
||||||
|
QfO5fi3e3amtkXyRU1CnXPh4ywtWmpvZtmoDqol13Zjjzjose2GGt4hpZsBggVHQ
|
||||||
|
6jPgrAENsQKBgHMYi7aV2ZyptEjky+UkZr59eA8Co7aCEBipllQlB3XCtTMbtuVy
|
||||||
|
keDQpgnYD3SHM01oPVxJoCUdmkoBDd8xuEYQjKUFTz4q5KFTpHahiCEcApvLqtGO
|
||||||
|
iORC6CSfSgVNFv8dKXWp72OfyzCGxCWlKI/U7VuD4pcMXpq2sTTFM1wRAoGBANZW
|
||||||
|
rr2a7ZHc0DTkTiaX4VcrRg40fTHX8mfJFxQ2fBgHusJj4TQ5kRCmFiFdhTB4g7uh
|
||||||
|
lbwn4AdQDZaFO9uCefBQyFE+7VBWHJMkDhQ6dYqi7BACQuOEaUyCRUa2rwoEUAgG
|
||||||
|
CGUxe3xhw9SP2FMaBIYjSWrqZ4bfEKKd9jYhNqeBAoGBAK9adFsDFQtT2O4u25hx
|
||||||
|
Yv7m9ZG5NbvhuQuEK7skdDb+HZHK/1JIV8WG16zTe897I7IC+OYezKLA1fbBnna0
|
||||||
|
rARwY/NZL1/CA5SmPGgK5Vy9IJbyJ50tQqFUGaF0SF/5jAuzCLa82d3XWUOlUgWH
|
||||||
|
zkITyIa3HhT//7eFdH3sa+Hc
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEWTCCAsGgAwIBAgIQBKpJXSm53rsT3EorgGHTXjANBgkqhkiG9w0BAQsFADCB
|
||||||
|
kzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMTQwMgYDVQQLDCtzdW5w
|
||||||
|
ZW5nQHN1bnBlbmdkZU1hY0Jvb2stUHJvLmxvY2FsICjlrZnpuY8pMTswOQYDVQQD
|
||||||
|
DDJta2NlcnQgc3VucGVuZ0BzdW5wZW5nZGVNYWNCb29rLVByby5sb2NhbCAo5a2Z
|
||||||
|
6bmPKTAeFw0yNTA3MTgwNzU0NTRaFw0yNzEwMTgwNzU0NTRaMF8xJzAlBgNVBAoT
|
||||||
|
Hm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTE0MDIGA1UECwwrc3VucGVu
|
||||||
|
Z0BzdW5wZW5nZGVNYWNCb29rLVByby5sb2NhbCAo5a2Z6bmPKTCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBAL8VdR8r6vLyFQkfeZiGUO6RdbTmQtNGPIx3
|
||||||
|
wbuzxC3cz0HV73avEc0pxTjn6VINMXxtvUkXoPMJeagKWif/ofxi8fMPdHLKmaoJ
|
||||||
|
GLXupDByHkm2mu1vyUIlVwEKUNQWOh5O09ekkxd0fk/GMtHoBrdngekGkgoyy+n1
|
||||||
|
loAbRdANNSjy6twh5XXqJGxF+otG5/BDiBWVXG44lVuYeYrIElmNr6IFWWyJUGCA
|
||||||
|
xAmrZrYdATguTaW/7u5apsnYysvx3xo6Qki35i2qXFWa/a8ugvDaEB3h6acXaKMU
|
||||||
|
Rgm03N6knlfSeW3MAdB365bjixONaUw6imoqmoPX5H1k2wyx26kCAwEAAaNcMFow
|
||||||
|
DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaA
|
||||||
|
FF75UQ00SANrn+spMSH1elRO+PN9MBIGA1UdEQQLMAmCB2luc3RhbGwwDQYJKoZI
|
||||||
|
hvcNAQELBQADggGBAF7D7B5a2ZZ4vSgqGx8e0p08dVfUHM3v85pHi7VO7xVaHKWh
|
||||||
|
rS09S5sTVvDiEOujHXlnrGYBQjOZ3/DwBJyNQQG83EWZ1/TWyYIrmBUUBzpaAJ+t
|
||||||
|
gLap5KaQoV+xo46PfXCG5bQmqllcsZKWvY5c8chECHXWJMX7cF8/9XBI7gywIoRN
|
||||||
|
PRVKoXjh5SAoOzI8VjnQ3gEXywnuBfaSu/76oNT9ty/Y94G6RhYLq+s0Hpj5FAi2
|
||||||
|
KbznwKAk14PfUDuZenPKac1NFNdlRnjaBoIQBtikSQjM9TaBMD1xvMhmxO779/0P
|
||||||
|
kBrtzJcYez/SOrTFGUWMaM9CQSqBrINOJah56QB0eP1o1NvnzV7L/2c0kDQVJMMM
|
||||||
|
oy+1Qfx9OhYvAv/xmORWNlGw+oF4bh71qqlWcQ3mqrYBsYIfxt/1MsYawtg3waer
|
||||||
|
h/CO5vPOlLplqW8H7hrU8e4zq9QRMSLlMNycYQs+S8JTlL42lT6a4dXDXBwx4NlP
|
||||||
|
QeQTR9ak1+yacEzE2w==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
@ -26,6 +26,12 @@ http {
|
||||||
'$status $body_bytes_sent "$http_referer" '
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
# 在http块添加main_cookie日志格式
|
||||||
|
log_format main_cookie '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||||
|
'cookie:"$http_cookie"';
|
||||||
|
|
||||||
# 访问日志
|
# 访问日志
|
||||||
access_log /tmp/nginx_access.log main;
|
access_log /tmp/nginx_access.log main;
|
||||||
|
|
||||||
|
|
@ -42,10 +48,10 @@ http {
|
||||||
gzip_min_length 1024;
|
gzip_min_length 1024;
|
||||||
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
|
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
|
||||||
|
|
||||||
# 前端应用服务器 (a.com) - HTTPS
|
# 前端应用服务器 (a.local.com) - HTTPS
|
||||||
server {
|
server {
|
||||||
listen 443 ssl;
|
listen 443 ssl;
|
||||||
server_name a.com;
|
server_name a.local.com;
|
||||||
|
|
||||||
# SSL配置
|
# SSL配置
|
||||||
ssl_certificate /Users/sunpeng/workspace/remote/oauth2/ssl/certificate.crt;
|
ssl_certificate /Users/sunpeng/workspace/remote/oauth2/ssl/certificate.crt;
|
||||||
|
|
@ -67,6 +73,11 @@ http {
|
||||||
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 防止前端server拦截OIDC登录页,/login直接返回404
|
||||||
|
location = /login {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
# 处理OPTIONS预检请求
|
# 处理OPTIONS预检请求
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||||
expires 1y;
|
expires 1y;
|
||||||
|
|
@ -82,14 +93,14 @@ http {
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
# 处理CORS
|
# 处理CORS
|
||||||
add_header Access-Control-Allow-Origin "https://a.com" always;
|
add_header Access-Control-Allow-Origin "https://a.local.com" always;
|
||||||
add_header Access-Control-Allow-Credentials "true" always;
|
add_header Access-Control-Allow-Credentials "true" always;
|
||||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
||||||
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
||||||
|
|
||||||
# 处理OPTIONS请求
|
# 处理OPTIONS请求
|
||||||
if ($request_method = 'OPTIONS') {
|
if ($request_method = 'OPTIONS') {
|
||||||
add_header Access-Control-Allow-Origin "https://a.com" always;
|
add_header Access-Control-Allow-Origin "https://a.local.com" always;
|
||||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
||||||
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
||||||
add_header Access-Control-Max-Age 1728000;
|
add_header Access-Control-Max-Age 1728000;
|
||||||
|
|
@ -108,14 +119,14 @@ http {
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
# 处理CORS
|
# 处理CORS
|
||||||
add_header Access-Control-Allow-Origin "https://a.com" always;
|
add_header Access-Control-Allow-Origin "https://a.local.com" always;
|
||||||
add_header Access-Control-Allow-Credentials "true" always;
|
add_header Access-Control-Allow-Credentials "true" always;
|
||||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
||||||
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
||||||
|
|
||||||
# 处理OPTIONS请求
|
# 处理OPTIONS请求
|
||||||
if ($request_method = 'OPTIONS') {
|
if ($request_method = 'OPTIONS') {
|
||||||
add_header Access-Control-Allow-Origin "https://a.com" always;
|
add_header Access-Control-Allow-Origin "https://a.local.com" always;
|
||||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
||||||
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
||||||
add_header Access-Control-Max-Age 1728000;
|
add_header Access-Control-Max-Age 1728000;
|
||||||
|
|
@ -125,15 +136,45 @@ http {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# /oidc-logout 路径转发到 OIDC 服务
|
||||||
|
location /oidc-logout {
|
||||||
|
proxy_pass http://localhost:9000/oidc-logout;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
|
||||||
|
# 记录cookie内容到专用日志
|
||||||
|
access_log /tmp/nginx_oidc_logout.log main_cookie;
|
||||||
|
|
||||||
|
# 处理CORS
|
||||||
|
add_header Access-Control-Allow-Origin "https://a.local.com" always;
|
||||||
|
add_header Access-Control-Allow-Credentials "true" always;
|
||||||
|
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||||||
|
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
||||||
|
|
||||||
|
# 处理OPTIONS请求
|
||||||
|
if ($request_method = 'OPTIONS') {
|
||||||
|
add_header Access-Control-Allow-Origin "https://a.local.com" always;
|
||||||
|
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||||||
|
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
||||||
|
add_header Access-Control-Max-Age 1728000;
|
||||||
|
add_header Content-Type "text/plain; charset=utf-8";
|
||||||
|
add_header Content-Length 0;
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# 错误页面
|
# 错误页面
|
||||||
error_page 404 /404.html;
|
error_page 404 /404.html;
|
||||||
error_page 500 502 503 504 /50x.html;
|
error_page 500 502 503 504 /50x.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
# OIDC服务器代理 (oidc.com) - HTTPS
|
# OIDC服务器代理 (oidc.local.com) - HTTPS
|
||||||
server {
|
server {
|
||||||
listen 443 ssl;
|
listen 443 ssl;
|
||||||
server_name oidc.com;
|
server_name oidc.local.com;
|
||||||
|
|
||||||
# SSL配置
|
# SSL配置
|
||||||
ssl_certificate /Users/sunpeng/workspace/remote/oauth2/ssl/certificate.crt;
|
ssl_certificate /Users/sunpeng/workspace/remote/oauth2/ssl/certificate.crt;
|
||||||
|
|
@ -144,25 +185,21 @@ http {
|
||||||
|
|
||||||
# 代理到OIDC服务器
|
# 代理到OIDC服务器
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://localhost:9000;
|
proxy_pass http://localhost:9000/;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Ssl on;
|
||||||
proxy_set_header Cookie $http_cookie;
|
proxy_set_header Cookie $http_cookie;
|
||||||
|
add_header Access-Control-Allow-Origin "https://a.local.com" always;
|
||||||
# 处理CORS
|
|
||||||
add_header Access-Control-Allow-Origin "https://a.com" always;
|
|
||||||
add_header Access-Control-Allow-Credentials "true" always;
|
add_header Access-Control-Allow-Credentials "true" always;
|
||||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
||||||
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
||||||
|
|
||||||
# 移除CSP限制 (开发环境)
|
|
||||||
add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: http: https:;" always;
|
|
||||||
|
|
||||||
# 处理OPTIONS请求
|
|
||||||
if ($request_method = 'OPTIONS') {
|
if ($request_method = 'OPTIONS') {
|
||||||
add_header Access-Control-Allow-Origin "https://a.com" always;
|
add_header Access-Control-Allow-Origin "https://a.local.com" always;
|
||||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
||||||
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
||||||
add_header Access-Control-Max-Age 1728000;
|
add_header Access-Control-Max-Age 1728000;
|
||||||
|
|
@ -180,7 +217,7 @@ http {
|
||||||
# HTTP重定向到HTTPS
|
# HTTP重定向到HTTPS
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name a.com oidc.com;
|
server_name a.local.com oidc.local.com;
|
||||||
return 301 https://$server_name$request_uri;
|
return 301 https://$server_name$request_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ public class SecurityConfig {
|
||||||
.requestMatchers("/oauth2/jwks").permitAll()
|
.requestMatchers("/oauth2/jwks").permitAll()
|
||||||
.requestMatchers("/logout").permitAll()
|
.requestMatchers("/logout").permitAll()
|
||||||
.requestMatchers("/login").permitAll()
|
.requestMatchers("/login").permitAll()
|
||||||
|
.requestMatchers("/oidc-logout").permitAll()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.oauth2ResourceServer(oauth2 -> oauth2.jwt()) // 新增,支持JWT
|
.oauth2ResourceServer(oauth2 -> oauth2.jwt()) // 新增,支持JWT
|
||||||
|
|
@ -112,14 +113,14 @@ public class SecurityConfig {
|
||||||
// 注册客户端(内存存储)
|
// 注册客户端(内存存储)
|
||||||
@Bean
|
@Bean
|
||||||
public RegisteredClientRepository registeredClientRepository(PasswordEncoder passwordEncoder) {
|
public RegisteredClientRepository registeredClientRepository(PasswordEncoder passwordEncoder) {
|
||||||
// a.com 前端应用的 client
|
// a.sun.com 前端应用的 client
|
||||||
RegisteredClient aClient = RegisteredClient.withId(UUID.randomUUID().toString())
|
RegisteredClient aClient = RegisteredClient.withId(UUID.randomUUID().toString())
|
||||||
.clientId("a-client")
|
.clientId("a-client")
|
||||||
.clientSecret(passwordEncoder.encode("a-secret"))
|
.clientSecret(passwordEncoder.encode("a-secret"))
|
||||||
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
||||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||||
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
|
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
|
||||||
.redirectUri("https://a.com/callback")
|
.redirectUri("https://a.local.com/callback")
|
||||||
.scope(OidcScopes.OPENID)
|
.scope(OidcScopes.OPENID)
|
||||||
.scope("read")
|
.scope("read")
|
||||||
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(false).build())
|
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(false).build())
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.tuoheng.oauth.oidc.controller;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class OidcLogoutController {
|
||||||
|
|
||||||
|
@GetMapping("/oidc-logout")
|
||||||
|
public String oidcLogout(
|
||||||
|
@RequestParam(value = "id_token_hint", required = false) String idTokenHint,
|
||||||
|
@RequestParam(value = "post_logout_redirect_uri", required = false) String redirectUri,
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
Authentication authentication) {
|
||||||
|
|
||||||
|
// 调用Spring Security的logout
|
||||||
|
new SecurityContextLogoutHandler().logout(request, response, authentication);
|
||||||
|
|
||||||
|
// 重定向到指定页面
|
||||||
|
if (redirectUri != null && !redirectUri.isEmpty()) {
|
||||||
|
return "redirect:" + redirectUri;
|
||||||
|
}
|
||||||
|
return "redirect:/login?logout";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
spring.application.name=oidc
|
spring.application.name=oidc
|
||||||
server.port=9000
|
server.port=9000
|
||||||
spring.security.oauth2.authorization-server.issuer-url: https://oidc.com
|
spring.security.oauth2.authorization-server.issuer-url: https://oidc.local.com
|
||||||
server.servlet.session.timeout=1m
|
server.servlet.session.timeout=1m
|
||||||
|
server.servlet.session.cookie.domain=local.com
|
||||||
|
server.forward-headers-strategy=framework
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
server.port=8081
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -63,9 +63,9 @@
|
||||||
const oidcConfig = {
|
const oidcConfig = {
|
||||||
clientId: 'a-client',
|
clientId: 'a-client',
|
||||||
clientSecret: 'a-secret',
|
clientSecret: 'a-secret',
|
||||||
redirectUri: 'https://a.com/callback',
|
redirectUri: 'https://a.local.com/callback',
|
||||||
tokenEndpoint: 'https://oidc.com/oauth2/token',
|
tokenEndpoint: 'https://oidc.local.com/oauth2/token',
|
||||||
userInfoEndpoint: 'https://oidc.com/userinfo'
|
userInfoEndpoint: 'https://oidc.local.com/userinfo'
|
||||||
};
|
};
|
||||||
|
|
||||||
// 页面加载时执行
|
// 页面加载时执行
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,10 @@
|
||||||
const oidcConfig = {
|
const oidcConfig = {
|
||||||
clientId: 'a-client',
|
clientId: 'a-client',
|
||||||
clientSecret: 'a-secret',
|
clientSecret: 'a-secret',
|
||||||
redirectUri: 'https://a.com/callback',
|
redirectUri: 'https://a.local.com/callback',
|
||||||
authorizationEndpoint: 'https://oidc.com/oauth2/authorize',
|
authorizationEndpoint: 'https://oidc.local.com/oauth2/authorize',
|
||||||
tokenEndpoint: 'https://oidc.com/oauth2/token',
|
tokenEndpoint: 'https://oidc.local.com/oauth2/token',
|
||||||
userInfoEndpoint: 'https://oidc.com/userinfo',
|
userInfoEndpoint: 'https://oidc.local.com/userinfo',
|
||||||
scope: 'openid read'
|
scope: 'openid read'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -110,7 +110,7 @@
|
||||||
|
|
||||||
// 验证token
|
// 验证token
|
||||||
function validateToken(token) {
|
function validateToken(token) {
|
||||||
fetch('https://oidc.com/userinfo', {
|
fetch('https://oidc.local.com/userinfo', {
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${token}`
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
|
|
@ -266,13 +266,21 @@
|
||||||
|
|
||||||
// 退出登录
|
// 退出登录
|
||||||
function logout() {
|
function logout() {
|
||||||
// 通过nginx代理调用logout
|
|
||||||
// 清理本地token
|
// 清理本地token
|
||||||
localStorage.removeItem('access_token');
|
localStorage.removeItem('access_token');
|
||||||
localStorage.removeItem('refresh_token');
|
localStorage.removeItem('refresh_token');
|
||||||
localStorage.removeItem('oauth_state');
|
localStorage.removeItem('oauth_state');
|
||||||
// 跳转到Spring Security默认的退出页面(GET)
|
// 获取id_token(如果有)
|
||||||
window.location.href = 'https://oidc.com/logout';
|
const idToken = localStorage.getItem('id_token'); // 登录时保存id_token
|
||||||
|
// 退出后跳转到首页
|
||||||
|
const redirectUri = encodeURIComponent('https://a.local.com');
|
||||||
|
// 拼接logout url
|
||||||
|
let logoutUrl = `https://a.local.com/oidc-logout?post_logout_redirect_uri=${redirectUri}`;
|
||||||
|
if (idToken) {
|
||||||
|
logoutUrl += `&id_token_hint=${idToken}`;
|
||||||
|
}
|
||||||
|
// 跳转到OIDC logout端点
|
||||||
|
window.location.href = logoutUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成随机字符串
|
// 生成随机字符串
|
||||||
|
|
|
||||||
|
|
@ -76,11 +76,11 @@
|
||||||
const oidcConfig = {
|
const oidcConfig = {
|
||||||
clientId: 'a-client',
|
clientId: 'a-client',
|
||||||
clientSecret: 'a-secret',
|
clientSecret: 'a-secret',
|
||||||
redirectUri: 'https://a.com/callback',
|
redirectUri: 'https://a.local.com/callback',
|
||||||
authorizationEndpoint: 'https://oidc.com/oauth2/authorize',
|
authorizationEndpoint: 'https://oidc.local.com/oauth2/authorize',
|
||||||
tokenEndpoint: 'https://oidc.com/oauth2/token',
|
tokenEndpoint: 'https://oidc.local.com/oauth2/token',
|
||||||
userInfoEndpoint: 'https://oidc.com/userinfo',
|
userInfoEndpoint: 'https://oidc.local.com/userinfo',
|
||||||
jwksEndpoint: 'https://oidc.com/oauth2/jwks',
|
jwksEndpoint: 'https://oidc.local.com/oauth2/jwks',
|
||||||
scope: 'openid read'
|
scope: 'openid read'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,26 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIID5jCCAs6gAwIBAgIUKxk4umxo+aYVDQ483sMNIjyV3iwwDQYJKoZIhvcNAQEL
|
MIIEaTCCAtGgAwIBAgIRAO0/byq8GJJoBReBXr16yJUwDQYJKoZIhvcNAQELBQAw
|
||||||
BQAwZDELMAkGA1UEBhMCQ04xEDAOBgNVBAgMB0JlaWppbmcxEDAOBgNVBAcMB0Jl
|
gZMxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTE0MDIGA1UECwwrc3Vu
|
||||||
aWppbmcxFDASBgNVBAoMC0RldmVsb3BtZW50MQswCQYDVQQLDAJJVDEOMAwGA1UE
|
cGVuZ0BzdW5wZW5nZGVNYWNCb29rLVByby5sb2NhbCAo5a2Z6bmPKTE7MDkGA1UE
|
||||||
AwwFKi5jb20wHhcNMjUwNzE4MDEyNTQzWhcNMjYwNzE4MDEyNTQzWjBkMQswCQYD
|
AwwybWtjZXJ0IHN1bnBlbmdAc3VucGVuZ2RlTWFjQm9vay1Qcm8ubG9jYWwgKOWt
|
||||||
VQQGEwJDTjEQMA4GA1UECAwHQmVpamluZzEQMA4GA1UEBwwHQmVpamluZzEUMBIG
|
mem5jykwHhcNMjUwNzE4MDc1ODM2WhcNMjcxMDE4MDc1ODM2WjBfMScwJQYDVQQK
|
||||||
A1UECgwLRGV2ZWxvcG1lbnQxCzAJBgNVBAsMAklUMQ4wDAYDVQQDDAUqLmNvbTCC
|
Ex5ta2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUxNDAyBgNVBAsMK3N1bnBl
|
||||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANmJXA4sFsmdGU36bN5ThBAJ
|
bmdAc3VucGVuZ2RlTWFjQm9vay1Qcm8ubG9jYWwgKOWtmem5jykwggEiMA0GCSqG
|
||||||
JZTY1vUaewmM41+IbSClPQEiO2/gK/tmDWBE82+IG7TEqbbLqUkORWFmp3bn0wgE
|
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDgP4hfcsywJ9SbioGTODJDSG8yx1djhPp4
|
||||||
nW3JamZMfPo43rr+3i9OmxPzQUMzIn5HTh9+QPxAPGUafbHJTcIc3ixCXHu150+6
|
yQZZ2jBqDHviF8rM+JcryTfR2Giuy9bi2ygNr18R8DDotFAp+S6LJRaS82rusiY4
|
||||||
Mh4v/fkRk6Yog93VIwpADYEyocVn8SkTzGn2FsF5R+hu/t+bGAO+e5iYiwlaheCj
|
+uvfptlBKF4/E967GHtPGN59LanP8d3k3aPevpdCnAKw94doPJFmEm328h28AQYE
|
||||||
yLfgzOuNo0jkxr1wmV2juN1CJ0nntqHaajMDqszQZXeBQ1K/UMgt2Ln2CRiQoatl
|
v+VeQEmYbYkpuOVT5eAjDKp+GFDx+zzXQN+U4domZPHZe0rCKFtPTHzk18yXuSTZ
|
||||||
UfeFBF/urK1VI8TrvayeMyMkXiAOxxvKLqbvLmvwKlr7iRtrE0SUsOdfjA4h788C
|
q2ssAcxP27QwPPusccND3oESyF46lEbVjxRvDIYXLOHxahN7RKsSXTHaGqpGsiUH
|
||||||
AwEAAaOBjzCBjDAdBgNVHQ4EFgQUZqqbZSCLhcMWDsRQYZ5/vYjPVFMwHwYDVR0j
|
Si2ppRRQmTzOMxkQB9ooW1Q2yatz5gzAq0dc8ft3VLowmloas6lPAgMBAAGjazBp
|
||||||
BBgwFoAUZqqbZSCLhcMWDsRQYZ5/vYjPVFMwDwYDVR0TAQH/BAUwAwEB/zA5BgNV
|
MA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAW
|
||||||
HREEMjAwggUqLmNvbYIFYS5jb22CBWIuY29tgghvaWRjLmNvbYIJbG9jYWxob3N0
|
gBRe+VENNEgDa5/rKTEh9XpUTvjzfTAhBgNVHREEGjAYggsqLmxvY2FsLmNvbYIJ
|
||||||
hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQC78BfqEOofJRjECXRLspkTRfz8LsN2
|
bG9jYWwuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAL7KrS2TMcOKIoMzTnFLv0skL9
|
||||||
EYu3bMvSmRjgbApY6Sh4Yg6LQUBRNkw17GMQ1WQTKVdygqZeQWYZvD1FgBHjoWwk
|
evEf+9rERDPVb/J/iplaV5y1RqZjQDU9vCvsjT2igf5Xcqipu0p33pqpHwnMehDx
|
||||||
3yfi9tfuWiD5XMWri7gpuF3xlizvSIgc0dR14J3w++1xB/jq030/wMPaYbgBqgIR
|
M37bxonJMLOYz91PLyPZPUt76YF5NoySBshXGo6o4+PmCHpMChrspXWT36hJmfX2
|
||||||
8z2KtnvpwJvLnifBJLJ3a3g24hyKkZ+Ye0/0f8aLMZtUBB99QY6PMe9E3GDnQbQi
|
8mMwkFA6iafHy0bV9Chy6h7lzymWd7XR21xMIVT25faf8hRbx/xZ/xUf0/tWlY8Q
|
||||||
4u4hPVzhWdxUQsoZ26NqgvobITx/hl7uKbr36NkGHUGgo9Vo+JEmy56HqZZjuwUK
|
wp01RWFVcP2OWgeZxttnALvgXnJPFH29S2seB2TmkuZcz6ogcuCnYH2CQCC/yL0d
|
||||||
w8a4/EK0wjjPR9ooj4TWfYWfTr6Bde6v0awLENqDGJpFNacxgXGesoA4
|
Y5YFzUqsmDaF5YUdFcwb6MTfIQOXyGLbTgBdqPgRVtxp76BTVV4nDP5IxjET6++C
|
||||||
|
QzhJ1teqZTLdPvXIa+yqXQ/EI1NKNNRAYtmduH5kHgR1vKrQDMSHEhTaIevjN037
|
||||||
|
2dJEdRYi47OQIocqd80StGuRNL51dAYYjB3hj0WpQpKlzc8TurB8JeVwjzn5H9pv
|
||||||
|
A0k1s/OvborcCUguZOwVglAaVlHadmANhoel+q0=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,28 @@
|
||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
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
|
||||||
2fBQ0cw3/nOQ3QRZpfP5XRxdWQ==
|
5t/fBrOuubfljuu9ULZjMc0=
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
eyJraWQiOiIyMjYyZjU4MS0wNzRiLTRmZDctOGM2OC1mNGY3ODU1OGEyZWYiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiYXVkIjoiY2xpZW50IiwibmJmIjoxNzUyNzM5MjUyLCJzY29wZSI6WyJvcGVuaWQiXSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo5MDAwIiwiZXhwIjoxNzUyNzM5ODUyLCJpYXQiOjE3NTI3MzkyNTIsImp0aSI6ImMwNTZkNjAxLTBlZWYtNDBjYy04ODdiLTdjNjg1NDZlMzY2MSJ9.YifGLvHLe2QMInBgdJmW_us3m-Q41XX8RyaUfCv7J9gKT22wFAFtXUeXhF1bHXn9XUoPd3I33uBFclsYSs5XPqWlBhpiE-drRsZT-ZzbZ-x0YEELTkBEabYj-wivzHZZ9sVOxdV3yV7dN8-GpGJGyDglbX8tcWziZ4hCmSWIVCipb9cezBZdQYJiXe5SKb4qSmsQzF8F1CbBHuckfwXkggwVitW2YVKaeFDkV99RZRmcNzcvwVc6VU59cPr7VeirRTvjUyZKzpy9D9qtexKkSp0Fp0S4-J1NRHYh5mfaOBGSIQ52LE7c5Vz0lg23E0qCG3QvFkGF2i01fAIbEIpGLA
|
||||||
Loading…
Reference in New Issue