实现oauth2

This commit is contained in:
2025-12-14 17:47:08 +08:00
parent d04440f0b1
commit d353735d1b
31 changed files with 2355 additions and 70 deletions

167
db/oauth2_schema.sql Normal file
View File

@@ -0,0 +1,167 @@
-- OAuth2/OIDC 单点登录 数据库表结构
-- 创建时间: 2025-12-14
-- =============================================
-- OAuth2 客户端表
-- =============================================
CREATE TABLE IF NOT EXISTS `oauth2_client` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`client_id` VARCHAR(100) NOT NULL COMMENT '客户端ID',
`client_secret` VARCHAR(255) NULL COMMENT '客户端密钥BCrypt加密公共客户端为NULL',
`client_name` VARCHAR(100) NOT NULL COMMENT '客户端名称',
`client_type` VARCHAR(20) NOT NULL COMMENT '客户端类型confidential机密/ public公共',
`redirect_uris` TEXT NOT NULL COMMENT '重定向URI列表JSON数组格式',
`post_logout_redirect_uris` TEXT COMMENT '登出后重定向URI列表JSON数组格式',
`allowed_scopes` VARCHAR(500) NOT NULL COMMENT '允许的作用域逗号分隔openid,profile,email',
`allowed_grant_types` VARCHAR(200) NOT NULL COMMENT '允许的授权类型逗号分隔authorization_code,refresh_token',
`access_token_ttl` INT DEFAULT 900 COMMENT 'Access Token有效期默认15分钟',
`refresh_token_ttl` INT DEFAULT 604800 COMMENT 'Refresh Token有效期默认7天',
`require_pkce` TINYINT(1) DEFAULT 1 COMMENT '是否要求PKCE1=要求0=不要求)',
`is_enabled` TINYINT(1) DEFAULT 1 COMMENT '是否启用1=启用0=禁用)',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_client_id` (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='OAuth2客户端表';
-- =============================================
-- 插入测试客户端数据
-- =============================================
-- 1. Web 应用(机密客户端)
-- client_secret 明文: web_app_secret_2024
-- BCrypt 加密后: $2a$10$XQw.gH7qKvYJ8pqXk7YRNe8xZYKZJ.3kZQH5.3zV4YXjQH5.3zV4Y
INSERT INTO `oauth2_client`
(`client_id`, `client_secret`, `client_name`, `client_type`,
`redirect_uris`, `post_logout_redirect_uris`,
`allowed_scopes`, `allowed_grant_types`,
`access_token_ttl`, `refresh_token_ttl`, `require_pkce`, `is_enabled`)
VALUES
('web-app',
'$2a$10$XQw.gH7qKvYJ8pqXk7YRNe8xZYKZJ.3kZQH5.3zV4YXjQH5.3zV4Y',
'Web应用',
'confidential',
'["http://localhost:3000/callback","http://localhost:3000/silent-renew","http://localhost:8080/callback"]',
'["http://localhost:3000/logout-callback","http://localhost:8080/logout"]',
'openid,profile,email',
'authorization_code,refresh_token',
900,
604800,
1,
1);
-- 2. 移动应用(公共客户端)
INSERT INTO `oauth2_client`
(`client_id`, `client_secret`, `client_name`, `client_type`,
`redirect_uris`, `post_logout_redirect_uris`,
`allowed_scopes`, `allowed_grant_types`,
`access_token_ttl`, `refresh_token_ttl`, `require_pkce`, `is_enabled`)
VALUES
('mobile-app',
NULL,
'移动应用',
'public',
'["acgoj://callback","acgoj://oauth/callback"]',
'["acgoj://logout","acgoj://oauth/logout"]',
'openid,profile',
'authorization_code,refresh_token',
900,
2592000, -- 30天
1, -- 强制要求PKCE
1);
-- 3. 管理后台(机密客户端)
-- client_secret 明文: admin_secret_2024
-- BCrypt 加密后: $2a$10$YRx.hI8rLwZK9qrYl8ZSOe9yAZLAK.4lARG6.4aW5ZYkRG6.4aW5A
INSERT INTO `oauth2_client`
(`client_id`, `client_secret`, `client_name`, `client_type`,
`redirect_uris`, `post_logout_redirect_uris`,
`allowed_scopes`, `allowed_grant_types`,
`access_token_ttl`, `refresh_token_ttl`, `require_pkce`, `is_enabled`)
VALUES
('admin-app',
'$2a$10$YRx.hI8rLwZK9qrYl8ZSOe9yAZLAK.4lARG6.4aW5ZYkRG6.4aW5A',
'管理后台',
'confidential',
'["http://localhost:3001/admin/callback","http://admin.acgoj.com/callback"]',
'["http://localhost:3001/admin/logout","http://admin.acgoj.com/logout"]',
'openid,profile,email,admin',
'authorization_code,refresh_token',
900,
604800,
1,
1);
-- =============================================
-- Redis 数据结构说明仅供参考Redis中存储
-- =============================================
-- 1. 授权码存储
-- Key: oauth2:auth_code:{code}
-- Value: JSON {
-- "code": "授权码",
-- "clientId": "客户端ID",
-- "userId": "用户ID",
-- "redirectUri": "重定向URI",
-- "scope": "授权范围",
-- "codeChallenge": "PKCE challenge",
-- "codeChallengeMethod": "S256",
-- "nonce": "防重放参数",
-- "expiresAt": 时间戳
-- }
-- TTL: 600秒10分钟
-- 2. 用户会话存储
-- Key: oauth2:session:{sessionId}
-- Value: JSON {
-- "sessionId": "会话ID",
-- "userId": "用户ID",
-- "clients": [
-- {
-- "clientId": "客户端ID",
-- "accessToken": "访问令牌",
-- "refreshToken": "刷新令牌",
-- "issuedAt": 时间戳
-- }
-- ],
-- "createdAt": 时间戳
-- }
-- TTL: 604800秒7天
-- 3. 用户会话索引
-- Key: oauth2:user_sessions:{userId}
-- Value: Set<sessionId>
-- TTL: 604800秒7天
-- 4. Token黑名单用于单点登出
-- Key: oauth2:token_blacklist:{SHA256(token)}
-- Value: "1"
-- TTL: Token的剩余有效期动态计算
-- 5. Refresh Token存储现有
-- Key: refresh_token:{userId}
-- Value: refresh_token字符串
-- TTL: 604800秒7天
-- =============================================
-- 索引说明
-- =============================================
-- 1. uk_client_id: 唯一索引确保client_id不重复
-- 2. 如需按client_name查询可添加: KEY `idx_client_name` (`client_name`)
-- 3. 如需按is_enabled查询可添加: KEY `idx_is_enabled` (`is_enabled`)
-- =============================================
-- 查询示例
-- =============================================
-- 查询所有启用的客户端
-- SELECT * FROM oauth2_client WHERE is_enabled = 1;
-- 根据client_id查询客户端
-- SELECT * FROM oauth2_client WHERE client_id = 'web-app';
-- 查询所有公共客户端
-- SELECT * FROM oauth2_client WHERE client_type = 'public';
-- 查询所有需要PKCE的客户端
-- SELECT * FROM oauth2_client WHERE require_pkce = 1;