php怎么实现单点登录_php跨域SSO解决方案【统一】

1次阅读

php实现单点登录必须解决三个前提:共享认证凭证(通过idp签发jwt)、可信身份断言传递(后端验签+校验iss/exp)、统一登出协调(idp回调sp登出接口清会话)。

php怎么实现单点登录_php跨域SSO解决方案【统一】

PHP 实现单点登录必须解决的三个前提

单点登录(SSO)不是靠一个 session_start() 就能跨域打通的。PHP 本身不处理跨域认证,它只是执行端——真正起作用的是「共享认证凭证」+「可信身份断言传递」+「统一登出协调」。没这三块,任何“SSO”都是伪方案。

常见错误现象:$_SESSION 在 A 域能读、B 域为空;用 setcookie() 写了同名 Cookie 却被浏览器拒绝(因 domain 不匹配或 SameSite 阻断);用户在 A 站登出,B 站仍能访问受保护资源。

  • 必须有一个独立的身份提供方(IdP),比如自建的 auth.example.com,所有应用(SP)只跟它通信,不互相信任
  • PHP 应用不能直接读写其他域名的 Cookie 或 Session,必须通过重定向 + Token(如 JWT)或后端代理方式交换身份声明
  • Session 生命周期要和 IdP 的 Token 有效期对齐,不能依赖 PHP 默认的 session.gc_maxlifetime 独立管理

用 JWT + OAuth2 实现轻量级跨域 SSO(推荐落地路径)

比起 SAML,JWT + OAuth2 更适合 PHP 中小项目:标准库支持好(firebase/php-jwt)、调试直观、前端也容易配合。关键不是“怎么生成 Token”,而是“谁签发、谁验证、怎么传”。

使用场景:多个子域(app1.example.comapp2.example.com)共用同一套登录页和用户中心。

立即学习PHP免费学习笔记(深入)”;

  • IdP 登录成功后,用私钥签发 JWT,payload 至少含 sub(用户唯一标识)、expiss(如 https://auth.example.com
  • SP(你的 PHP 应用)收到前端传来的 Authorization: Bearer <token></token> 后,用 IdP 公钥验签,再检查 issexp,**不解析就信任**
  • 避免把 JWT 存在前端 localStorage —— 改用 httpOnly Cookie(SameSite=LaxDomain=.example.com),由 PHP 后端透传给 IdP 验证接口
  • 注意 openssl_pkey_get_public() 加载公钥失败时不会报错,要用 openssl_error_string() 主动捕获

PHP 中处理跨域登出同步的坑

登出不是删掉自己 $_SESSION 就完事。用户在 app1.example.com 点登出,app2.example.com 的会话还在,这是最常被忽略的环节。

错误做法:前端跳转到 https://auth.example.com/logout 后就认为结束;结果 IdP 清了主会话,但各 SP 没通知到,session_destroy() 根本没触发。

  • IdP 登出时,必须记录当前在线 SP 列表(比如从上次登录时的 redirect_uri 域名提取并缓存)
  • PHP 应用需暴露一个后端登出回调接口(如 /sso-logout),IdP 用 curl POST 调用,带一次性 logout_token(JWT 格式,含 jti 防重放)
  • 这个接口里必须调用 session_unset() + session_destroy() + setcookie() 清空本地会话 Cookie,且 Domain 参数要和登录时一致(如 .example.com
  • 别依赖前端 js 发起登出请求——网络失败或用户关闭页面会导致同步中断

为什么不要自己实现 Cookie 共享或 session_id 透传

看到 “PHP 跨域 SSO” 就想改 session.cookie_domain 或拼接 PHPSESSID 传参?这基本等于放弃安全边界。

典型错误现象:session_start()Failed to decode session Object;不同子域间 session_id() 相同但数据读不到;csrf token 失效。

  • session.cookie_domain = ".example.com" 只解决同根域名下的 Cookie 共享,无法解决跨协议(http/https)、跨端口、或完全不同的域名(如 admin.netuser.org
  • 手动传 PHPSESSID via URL 或 POST 是严重反模式:Token 泄露风险高,且现代浏览器对第三方 Cookie 限制越来越严(SameSite=Strict 默认生效)
  • PHP 的 session_set_save_handler() 自定义存储看似灵活,但一旦 IdP 重启或密钥轮换,所有 SP 的 session 数据就不可解,维护成本爆炸

复杂点在于:SSO 不是功能模块,是架构约定。每个 PHP 应用都得按同一套 Token 结构、错误码、超时逻辑来写验证逻辑。最容易被忽略的,是 IdP 和各 SP 之间时钟不同步导致的 exp 校验失败——别忘了加个 1~2 分钟的 leeway

text=ZqhQzanResources