使用PHP实现免凭证跨站用户身份认证方案咨询
跨站点身份互通(单点登录SSO)落地实现方案
核心实现逻辑
你描述的场景属于典型的**中央认证源单点登录(SSO)**逻辑,不需要引入复杂的第三方组件,基于你现有的PHP+MySQL技术栈就可以快速实现,核心思路是将主站作为唯一的身份校验入口,所有关联站点的身份验证都委托给主站完成,通过带时效的单次授权码完成身份信息的安全传递。
具体落地步骤
1. 主站侧改造&开发内容
原有注册、登录逻辑不需要做大幅调整,只需要新增4个能力即可:
- 统一登录页适配回调逻辑:在原有登录地址增加
redirect_uri参数接收,用户登录成功后,自动跳转回该回调地址,同时携带临时授权码code - 临时授权码生成逻辑:用户登录成功后,生成一个10分钟内有效的随机字符串作为
code,和当前登录用户ID、过期时间、关联站点域名(校验用)一起存入MySQL的sso_auth_code表,避免授权码被恶意冒用 - 授权码校验接口:提供公共接口接收关联站点传递的
code,校验code是否有效、是否过期、来源域名是否匹配,校验通过后返回用户公开信息(用户名、头像等),同时立即销毁该code(单次有效,防止复用)
简化的主站校验接口示例代码:
// 主站 sso_check_code.php header('Content-Type: application/json'); $code = $_GET['code'] ?? ''; $client_domain = $_SERVER['HTTP_REFERER'] ? parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) : ''; // 数据库查询授权码信息 $stmt = $pdo->prepare("SELECT user_id, expire_time, allow_domain FROM sso_auth_code WHERE code = ?"); $stmt->execute([$code]); $auth_info = $stmt->fetch(PDO::FETCH_ASSOC); // 校验失败直接返回 if (!$auth_info || time() > $auth_info['expire_time'] || $auth_info['allow_domain'] != $client_domain) { echo json_encode(['code' => 403, 'msg' => '授权无效']); exit; } // 获取用户信息 $user_stmt = $pdo->prepare("SELECT username FROM users WHERE id = ?"); $user_stmt->execute([$auth_info['user_id']]); $user = $user_stmt->fetch(PDO::FETCH_ASSOC); // 销毁授权码,禁止复用 $pdo->prepare("DELETE FROM sso_auth_code WHERE code = ?")->execute([$code]); echo json_encode(['code' => 200, 'data' => $user]);
- 登录状态静默校验接口:给关联站点提供免跳转的登录状态检测能力,方便后续关联站点静默刷新用户身份状态。
2. 关联站点侧开发内容
只需要新增全局身份校验逻辑即可,不需要改动原有业务代码:
- 全局中间件校验本地登录状态:所有页面请求进来先校验本地Session是否有用户登录信息,有则直接使用;没有则进入SSO认证流程
- 认证跳转+授权码校验逻辑:如果本地没有登录状态,先判断请求参数里是否有主站返回的
code,有则请求主站校验接口获取用户信息写入本地Session,没有则直接跳转到主站登录页,同时携带当前页面地址作为回调参数
简化的关联站全局校验示例代码:
// 关联站 全局公共校验逻辑 session_start(); if (!isset($_SESSION['username'])) { // 存在主站返回的授权码则先校验 if (isset($_GET['code'])) { $code = $_GET['code']; // 请求主站校验接口获取用户信息 $user_info = file_get_contents("https://主站域名/sso_check_code.php?code=" . $code); $user_info = json_decode($user_info, true); if ($user_info['code'] == 200) { $_SESSION['username'] = $user_info['data']['username']; // 移除URL里的code参数,刷新当前页面 header('Location: ' . strtok($_SERVER["REQUEST_URI"], '?')); exit; } } // 没有授权码或者校验失败,跳转主站登录 $redirect_uri = urlencode("https://关联站域名" . $_SERVER['REQUEST_URI']); header("Location: https://主站域名/login.php?redirect_uri=" . $redirect_uri . "&client_id=提前约定的站点标识"); exit; }
3. 必须做的安全优化
- 所有回调地址
redirect_uri必须在主站做白名单校验,禁止跳转到未授权的站点,避免钓鱼攻击 - 临时授权码必须是短时效、单次有效,禁止设置长期有效的授权码
- 主站和关联站的接口请求如果涉及敏感信息,建议改用POST方式加签名校验,不要用明文GET传参
- 如果后续需要扩展更多关联站点、多端登录能力,可以直接对接标准OAuth2.0或者JWT协议,底层逻辑和上述实现思路完全一致。
内容的提问来源于stack exchange,提问作者Star_Amazing
相关产品推荐
相关产品推荐

