SET NAMES utf8mb4; CREATE TABLE IF NOT EXISTS admin_oauth_identities ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, provider VARCHAR(20) NOT NULL, subject VARCHAR(191) NOT NULL, admin_user_id BIGINT UNSIGNED NOT NULL, email VARCHAR(255) NOT NULL DEFAULT '', display_name VARCHAR(100) NOT NULL DEFAULT '', avatar_url VARCHAR(500) NOT NULL DEFAULT '', last_login_at DATETIME(3) NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (id), UNIQUE KEY uk_admin_oauth_provider_subject (provider, subject), UNIQUE KEY uk_admin_oauth_user_provider (admin_user_id, provider), CONSTRAINT fk_admin_oauth_identity_user FOREIGN KEY (admin_user_id) REFERENCES admin_users(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS admin_oauth_states ( state_hash BINARY(32) NOT NULL, provider VARCHAR(20) NOT NULL, code_verifier VARCHAR(128) NOT NULL DEFAULT '', expires_at DATETIME(3) NOT NULL, used_at DATETIME(3) NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (state_hash), KEY idx_admin_oauth_state_expiry (expires_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS admin_oauth_login_codes ( code_hash BINARY(32) NOT NULL, provider VARCHAR(20) NOT NULL, subject VARCHAR(191) NOT NULL, email VARCHAR(255) NOT NULL DEFAULT '', display_name VARCHAR(100) NOT NULL DEFAULT '', avatar_url VARCHAR(500) NOT NULL DEFAULT '', admin_user_id BIGINT UNSIGNED NULL, expires_at DATETIME(3) NOT NULL, used_at DATETIME(3) NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (code_hash), KEY idx_admin_oauth_code_expiry (expires_at), KEY idx_admin_oauth_code_admin (admin_user_id), CONSTRAINT fk_admin_oauth_code_user FOREIGN KEY (admin_user_id) REFERENCES admin_users(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO system_configs (config_key, config_value, value_type, description) VALUES ('oauth.admin.frontend_callback_url', 'http://localhost:5560/auth/social-callback', 'string', '第三方登录完成后跳转的管理端页面;生产环境必须使用 HTTPS'), ('oauth.wechat.enabled', 'false', 'boolean', '启用微信扫码登录'), ('oauth.wechat.client_id', '', 'string', '微信开放平台网站应用 AppID'), ('oauth.wechat.client_secret', '', 'secret', '微信开放平台网站应用 AppSecret'), ('oauth.wechat.authorization_url', 'https://open.weixin.qq.com/connect/qrconnect', 'string', '微信登录授权地址'), ('oauth.wechat.token_url', 'https://api.weixin.qq.com/sns/oauth2/access_token', 'string', '微信登录令牌地址'), ('oauth.wechat.userinfo_url', 'https://api.weixin.qq.com/sns/userinfo', 'string', '微信用户信息地址'), ('oauth.wechat.scope', 'snsapi_login', 'string', '微信网站应用登录授权范围'), ('oauth.wechat.redirect_uri', 'http://127.0.0.1:8888/admin/v1/auth/oauth/callback', 'string', '微信开放平台登记的授权回调地址;生产环境必须使用 HTTPS'), ('oauth.qq.enabled', 'false', 'boolean', '启用 QQ 登录'), ('oauth.qq.client_id', '', 'string', 'QQ 互联应用 AppID'), ('oauth.qq.client_secret', '', 'secret', 'QQ 互联应用 AppKey'), ('oauth.qq.authorization_url', 'https://graph.qq.com/oauth2.0/authorize', 'string', 'QQ 登录授权地址'), ('oauth.qq.token_url', 'https://graph.qq.com/oauth2.0/token', 'string', 'QQ 登录令牌地址'), ('oauth.qq.openid_url', 'https://graph.qq.com/oauth2.0/me', 'string', 'QQ OpenID 查询地址'), ('oauth.qq.userinfo_url', 'https://graph.qq.com/user/get_user_info', 'string', 'QQ 用户信息地址'), ('oauth.qq.scope', 'get_user_info', 'string', 'QQ 登录授权范围'), ('oauth.qq.redirect_uri', 'http://127.0.0.1:8888/admin/v1/auth/oauth/callback', 'string', 'QQ 互联登记的授权回调地址;生产环境必须使用 HTTPS'), ('oauth.github.enabled', 'false', 'boolean', '启用 GitHub 登录'), ('oauth.github.client_id', '', 'string', 'GitHub OAuth App Client ID'), ('oauth.github.client_secret', '', 'secret', 'GitHub OAuth App Client Secret'), ('oauth.github.authorization_url', 'https://github.com/login/oauth/authorize', 'string', 'GitHub OAuth 授权地址'), ('oauth.github.token_url', 'https://github.com/login/oauth/access_token', 'string', 'GitHub OAuth 令牌地址'), ('oauth.github.userinfo_url', 'https://api.github.com/user', 'string', 'GitHub 当前用户信息地址'), ('oauth.github.scope', 'read:user user:email', 'string', 'GitHub 登录最小授权范围'), ('oauth.github.redirect_uri', 'http://127.0.0.1:8888/admin/v1/auth/oauth/callback', 'string', 'GitHub OAuth App 登记的 callback URL;生产环境必须使用 HTTPS'), ('oauth.google.enabled', 'false', 'boolean', '启用 Google 登录'), ('oauth.google.client_id', '', 'string', 'Google OAuth 2.0 Client ID'), ('oauth.google.client_secret', '', 'secret', 'Google OAuth 2.0 Client Secret'), ('oauth.google.authorization_url', 'https://accounts.google.com/o/oauth2/v2/auth', 'string', 'Google OAuth 授权地址'), ('oauth.google.token_url', 'https://oauth2.googleapis.com/token', 'string', 'Google OAuth 令牌地址'), ('oauth.google.userinfo_url', 'https://openidconnect.googleapis.com/v1/userinfo', 'string', 'Google OpenID Connect UserInfo 地址'), ('oauth.google.scope', 'openid profile email', 'string', 'Google 登录授权范围'), ('oauth.google.redirect_uri', 'http://127.0.0.1:8888/admin/v1/auth/oauth/callback', 'string', 'Google Cloud Console 登记的 redirect URI;生产环境必须使用 HTTPS') ON DUPLICATE KEY UPDATE description = VALUES(description);