-- 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 -- 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;