Laravel跨子域不同认证guard的一键登录如何实现?
Laravel 跨子域跨Guard 合作伙伴代登店铺后台实现方案
现有项目基础配置
- 双角色独立子域名:店铺管理后台为
abc.test,合作伙伴后台为partners.abc.test- 双独立认证Guard:店铺管理员使用默认
webGuard,合作伙伴使用partnersGuard- 业务规则:合作伙伴获得某店铺访问权限时,会被添加为该店铺的协作者,有权限的店铺会展示在合作伙伴后台列表,列表项配置「登录」按钮,点击后直接跳转登录对应店铺的管理后台
核心实现思路
整套逻辑基于短时效、一次性、带签名的临时凭证跳转实现,完全不传递账号密码、不暴露可硬构造的登录链接,从根源上避免安全风险,核心是分两段链路完成登录状态的衔接:
- 合作伙伴后台侧完成身份校验、权限校验,生成专属的临时跳转凭证
- 店铺管理后台侧校验凭证合法性,自动完成web Guard的登录态写入后跳转后台首页
具体实现步骤
第一步:在合作伙伴后台生成签名跳转链接
在partners.abc.test的店铺列表渲染环节,为每个有权限的店铺生成专属的登录跳转链接,禁止使用通用固定链接:
- 新增受
partnersGuard保护的跳转中转路由,路由形式参考:partners/shop/{shop}/sso-entry- 路由中间件必须绑定
auth:partners,确保只有已登录的合作伙伴才能访问该接口 - 接口内首先做二次权限校验:查询协作者关联表,确认当前登录的合作伙伴和路由传入的
shopID存在有效关联,直接拦截无权限的请求
- 路由中间件必须绑定
- 使用Laravel自带的临时签名路由功能生成跳转目标链接,直接对接店铺后台的SSO登录接口,参考生成代码:
// 生成2分钟有效期的签名链接,指向店铺后台的SSO入口 $ssoUrl = URL::temporarySignedRoute( 'shop.sso.auto-login', now()->addMinutes(2), [ 'shop_id' => $shop->id, 'partner_id' => auth('partners')->id() ] ); - 列表页的「登录」按钮直接绑定这个生成的
ssoUrl,不要拼接其他参数
第二步:在店铺后台实现自动登录接收接口
在主域abc.test的路由组下新增SSO接收接口,不要将该接口放到partners子域的路由组中:
- 路由定义参考:
sso/shop/auto-login,给路由起命名为shop.sso.auto-login,和之前生成签名链接的路由名对应 - 路由必须绑定
signed中间件,自动校验链接的签名完整性、是否过期,拦截被篡改、超期的请求 - 接口处理逻辑:
- 从请求参数中取出
shop_id,查询对应店铺绑定的主管理员账号(和业务规则匹配:每个店铺的管理员账号和店铺ID一一绑定) - 新增
sso_tokens数据表做防重放校验:表结构包含token、shop_id、partner_id、used_at、expired_at字段,每次生成临时凭证时同步写入未使用的令牌记录,接口收到请求时校验当前令牌是否已被使用,已使用的直接拦截 - 调用web Guard的登录方法,直接写入对应店铺管理员的登录态:
Auth::guard('web')->login($shopAdminUser, $remember = false),这一步会自动将web Guard的会话Cookie写入主域域名下 - 将当前使用的sso令牌标记为已使用,最后重定向到该店铺的管理后台首页
- 从请求参数中取出
关键配置注意事项
- 跨子域Cookie配置:将两个Guard的会话Cookie域名配置为
.abc.test(注意前缀的英文点),保证同根域下的Cookie基础配置统一,同时利用两个Guard本身的会话存储键隔离性,避免web Guard和partners Guard的登录态互相覆盖 - 坚决避免反模式实现:不要直接在URL中传递店铺管理员的用户ID,也不要生成长期有效的固定登录链接,这类无签名、无时效、无防重放的链接一旦泄露,会导致任意人可以直接登录店铺管理员账号
- 权限校验环节不能省略:即使是经过签名校验的请求,也要在最终登录环节二次确认关联的合作伙伴确实是对应店铺的有效协作者,防止被篡改shop_id参数跳转到无权限的店铺
内容的提问来源于stack exchange,提问作者rajathans
相关产品推荐
相关产品推荐

