-- 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 '是否要求PKCE（1=要求，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;
