登录
首页 >  文章 >  php教程

PHP实现单点登录跨域会话验证方法

时间:2026-01-05 13:19:33 296浏览 收藏

“纵有疾风来,人生不言弃”,这句话送给正在学习文章的朋友们,也希望在阅读本文《PHP实现单点登录及跨域会话验证方案》后,能够真的帮助到大家。我也会在后续的文章中,陆续更新文章相关的技术文章,有好的建议欢迎大家在评论留言,非常感谢!

单点登录通过中心认证服务实现跨域身份验证,用户在SSO Server登录后获取一次性ticket,经重定向传递至客户端,客户端通过验证接口校验ticket并建立本地会话,利用Redis存储ticket信息并设置过期时间,结合HTTPS、来源校验等机制保障安全,登出时由中心通知各客户端销毁会话。

php如何实现单点登录功能_php跨域名共享会话ticket验证方案

单点登录(SSO)的核心是让用户在一个系统中登录后,访问其他关联的系统时无需重复登录。在 PHP 中实现跨域名的 SSO,关键在于如何安全地共享用户身份凭证(ticket),尤其是在不同域名之间无法直接共享 Cookie 的情况下。

基本原理:基于中心认证服务的 Ticket 验证

搭建一个独立的认证中心(SSO Server),所有子系统(Client A、Client B 等)都信任该中心。用户首次访问任意子系统时,被重定向到 SSO Server 登录。登录成功后,SSO Server 发放一个一次性 ticket,并通过回调方式通知原系统完成身份确认。

典型流程如下:
  • 用户访问 client-a.com,未登录,跳转至 sso-server.com?redirect=client-a.com/callback
  • 用户在 sso-server.com 输入账号密码登录
  • 登录成功,sso-server.com 生成唯一 ticket(如 tkt-abc123),存储在服务端(Redis 推荐)并设置有效期
  • 重定向回 client-a.com/callback?ticket=tkt-abc123
  • client-a.com 收到 ticket,向 sso-server.com/api/validate 发起请求验证 ticket 合法性
  • sso-server 验证通过后返回用户信息,并标记该 ticket 已使用(防止重放攻击)
  • client-a.com 创建本地会话,用户登录成功

跨域名共享的关键:Ticket 传递与验证

由于 Cookie 不可跨域共享(如 client-a.com 无法读取 client-b.com 的 session),必须依赖中心服务器进行身份仲裁。ticket 是一次性的,通过 URL 参数传递,安全性较高。

实现要点:
  • Ticket 存储: 使用 Redis 存储 ticket 与用户信息的映射,设置自动过期时间(如 5 分钟)
  • 验证接口: SSO Server 提供 /api/validate?t=xxx 接口,返回 JSON 格式数据(是否有效、用户 ID、用户名等)
  • HTTPS 必须启用: 所有通信需走 HTTPS,防止 ticket 被窃听
  • Referer 或签名校验: 可增加来源域名白名单或请求签名,防止伪造验证请求

PHP 实现示例片段

SSO Server 生成 ticket(登录成功后):

$ticket = 'tkt_' . bin2hex(random_bytes(16));
$userId = 123;
// 存入 Redis,5分钟过期
$redis->setex($ticket, 300, json_encode(['user_id' => $userId, 'used' => false]));
header('Location: ' . $_GET['redirect'] . '?ticket=' . $ticket);

Client 端验证 ticket:

if (isset($_GET['ticket'])) {
  $ticket = $_GET['ticket'];
  $response = file_get_contents("https://sso-server.com/api/validate?t={$ticket}");
  $data = json_decode($response, true);
  if ($data['valid'] && !$data['used']) {
    $_SESSION['user_id'] = $data['user_id'];
    // 标记 ticket 已使用(由 server 完成)
  }
}

SSO Server 验证接口(/api/validate):

$t = $_GET['t'];
$data = $redis->get($t);
if (!$data) {
  echo json_encode(['valid' => false]); exit;
}
$info = json_decode($data, true);
if ($info['used']) {
  echo json_encode(['valid' => false]); exit;
}
// 标记为已使用,防止重放
$info['used'] = true;
$redis->setex($t, 300, json_encode($info)); // 更新状态
echo json_encode(['valid' => true, 'user_id' => $info['user_id']]);

登出处理

登出需要通知所有已登录的客户端。可在 SSO Server 记录用户的 active sessions,登出时向各 client 发起异步登出请求(如 client-a.com/sso/logout?token=xxx),各 client 销毁本地 session。

基本上就这些。核心是信任中心 + 一次性 ticket + 安全传输。不复杂但容易忽略细节,比如 ticket 过期、重放、来源校验等。

以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于文章的相关知识,也可关注golang学习网公众号。

前往漫画官网入口并下载 ➜
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>