Laravel单点登录和多端认证源码如何编写?

2026-05-03 00:193阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1170个文字,预计阅读时间需要5分钟。

Laravel单点登录和多端认证源码如何编写?

由于默认行为仅清除当前会话,不触及数据库中的+session+记录或其他设备的+token+,Laravel的+session+驱动(如file或redis)本身不提供跨设备会话管理能力。+logout()+函数仅删除当前请求绑定的session ID对应的数据,其他设备仍然可能持有旧的token进行访问。

常见错误现象:Auth::logout() 后,手机端或另一个浏览器仍能正常调用 API、访问受保护路由;后台查 personal_access_tokens 表发现旧 token 还在且未过期。

  • 必须主动失效所有该用户的 token,不能只依赖 session 清除
  • 如果用的是 Sanctum,要删 personal_access_tokens 表中对应 tokenable_idtokenable_type 的记录
  • 如果用 Passport,得调用 $user->tokens()->delete(),而不是只删当前 token
  • 注意:删 token 后,正在使用的 API 请求会在下一次验证时失败(401),但不会“实时中断”已建立的连接

Sanctum 实现单点登录:覆盖 createToken() 并清理旧 token

Sanctum 默认允许一个用户无限创建 token,不做互斥控制。要实现单点登录,得在生成新 token 前,把该用户所有已有 token 干掉——这是最直接、副作用最小的做法。

使用场景:App 登录、网页登录共用同一套 Sanctum token 体系,要求新登录即作废旧登录。

  • 在登录逻辑里,不要直接调用 $user->createToken('api-token')
  • 先执行 $user->currentAccessToken()->delete()(如果存在)或更稳妥地删全部:$user->tokens()->delete()
  • 再调用 $user->createToken('api-token') 生成新 token
  • 注意 tokens() 关系默认是 HasApiTokens trait 提供的,确保模型用了这个 trait
  • 性能影响极小,单次 DB delete 操作,无 N+1 问题

Passport 单点登录的关键:别漏掉 refresh_tokenaccess_token 的级联清理

Passport 的 token 是成对存在的:access_token + refresh_token,且 refresh_token 可用于续签。只删 access_token,用户还能用 refresh_token 换新 access_token,等于没踢干净。

常见错误现象:调用 $user->tokens()->delete() 后,前端用旧 refresh_token 仍能成功请求 /oauth/token 拿到新 access_token。

  • Passport 的 tokens() 关系默认只关联 oauth_access_tokens 表,不自动连带删 oauth_refresh_tokens
  • 必须手动删 refresh token:DB::table('oauth_refresh_tokens')->where('access_token_id', $tokenId)->delete(),或更稳妥地按 user_id 批量删
  • 推荐做法:用 $user->tokens()->with(['refreshToken']) 加载后遍历删除,或直接两表联合 delete(需确认外键约束)
  • 兼容性注意:Laravel 10+ 的 Passport 11+ 中 refresh_token 表结构有变更,字段名从 access_token_id 改为 access_token_id(不变),但逻辑一致

Session 驱动下怎么让多端登出同步?别只信 Session::flush()

基于 session 的 Web 登录(比如 web guard),Session::flush()Auth::logout() 只清当前请求的 session 数据,不影响其他设备的 session 文件或 redis key。要真正“踢人”,得从存储层下手。

使用场景:用户在电脑上点“退出登录”,希望手机网页也立刻失效。

  • session 存 Redis 时,可用 Redis::keys("laravel_session*") 扫描并匹配 user_id 字段(前提是 session 内存了 user_id)——但不推荐,性能差且不可靠
  • 更稳的方式:在用户表加 last_login_atsession_version 字段,中间件里每次请求都比对,不一致就强制登出
  • 或者用缓存标记:登录时写 Cache::put("user:{$id}:session_version", $uuid, 3600),登出时 Cache::forget(...),所有请求前校验该值是否匹配 session 里存的版本
  • 关键点:session 本身无中心状态,单点登录必须引入额外状态存储,否则纯靠 session 驱动做不到真正同步
事情说清了就结束。真正麻烦的不是删 token,而是你怎么定义“同一个用户”——是按 user_id?还是 device_id + user_id?要不要支持“保留当前设备,踢其他”?这些逻辑得自己兜底,框架不替你决定。
标签:Laravel

本文共计1170个文字,预计阅读时间需要5分钟。

Laravel单点登录和多端认证源码如何编写?

由于默认行为仅清除当前会话,不触及数据库中的+session+记录或其他设备的+token+,Laravel的+session+驱动(如file或redis)本身不提供跨设备会话管理能力。+logout()+函数仅删除当前请求绑定的session ID对应的数据,其他设备仍然可能持有旧的token进行访问。

常见错误现象:Auth::logout() 后,手机端或另一个浏览器仍能正常调用 API、访问受保护路由;后台查 personal_access_tokens 表发现旧 token 还在且未过期。

  • 必须主动失效所有该用户的 token,不能只依赖 session 清除
  • 如果用的是 Sanctum,要删 personal_access_tokens 表中对应 tokenable_idtokenable_type 的记录
  • 如果用 Passport,得调用 $user->tokens()->delete(),而不是只删当前 token
  • 注意:删 token 后,正在使用的 API 请求会在下一次验证时失败(401),但不会“实时中断”已建立的连接

Sanctum 实现单点登录:覆盖 createToken() 并清理旧 token

Sanctum 默认允许一个用户无限创建 token,不做互斥控制。要实现单点登录,得在生成新 token 前,把该用户所有已有 token 干掉——这是最直接、副作用最小的做法。

使用场景:App 登录、网页登录共用同一套 Sanctum token 体系,要求新登录即作废旧登录。

  • 在登录逻辑里,不要直接调用 $user->createToken('api-token')
  • 先执行 $user->currentAccessToken()->delete()(如果存在)或更稳妥地删全部:$user->tokens()->delete()
  • 再调用 $user->createToken('api-token') 生成新 token
  • 注意 tokens() 关系默认是 HasApiTokens trait 提供的,确保模型用了这个 trait
  • 性能影响极小,单次 DB delete 操作,无 N+1 问题

Passport 单点登录的关键:别漏掉 refresh_tokenaccess_token 的级联清理

Passport 的 token 是成对存在的:access_token + refresh_token,且 refresh_token 可用于续签。只删 access_token,用户还能用 refresh_token 换新 access_token,等于没踢干净。

常见错误现象:调用 $user->tokens()->delete() 后,前端用旧 refresh_token 仍能成功请求 /oauth/token 拿到新 access_token。

  • Passport 的 tokens() 关系默认只关联 oauth_access_tokens 表,不自动连带删 oauth_refresh_tokens
  • 必须手动删 refresh token:DB::table('oauth_refresh_tokens')->where('access_token_id', $tokenId)->delete(),或更稳妥地按 user_id 批量删
  • 推荐做法:用 $user->tokens()->with(['refreshToken']) 加载后遍历删除,或直接两表联合 delete(需确认外键约束)
  • 兼容性注意:Laravel 10+ 的 Passport 11+ 中 refresh_token 表结构有变更,字段名从 access_token_id 改为 access_token_id(不变),但逻辑一致

Session 驱动下怎么让多端登出同步?别只信 Session::flush()

基于 session 的 Web 登录(比如 web guard),Session::flush()Auth::logout() 只清当前请求的 session 数据,不影响其他设备的 session 文件或 redis key。要真正“踢人”,得从存储层下手。

使用场景:用户在电脑上点“退出登录”,希望手机网页也立刻失效。

  • session 存 Redis 时,可用 Redis::keys("laravel_session*") 扫描并匹配 user_id 字段(前提是 session 内存了 user_id)——但不推荐,性能差且不可靠
  • 更稳的方式:在用户表加 last_login_atsession_version 字段,中间件里每次请求都比对,不一致就强制登出
  • 或者用缓存标记:登录时写 Cache::put("user:{$id}:session_version", $uuid, 3600),登出时 Cache::forget(...),所有请求前校验该值是否匹配 session 里存的版本
  • 关键点:session 本身无中心状态,单点登录必须引入额外状态存储,否则纯靠 session 驱动做不到真正同步
事情说清了就结束。真正麻烦的不是删 token,而是你怎么定义“同一个用户”——是按 user_id?还是 device_id + user_id?要不要支持“保留当前设备,踢其他”?这些逻辑得自己兜底,框架不替你决定。
标签:Laravel