简介
本文件面向 DouPHP 社交登录插件系统,系统性说明 OAuth2.0/OIDC 接入、统一抽象层、用户信息同步、账号绑定、权限与会话安全等机制。文档覆盖 Google、QQ、微信、Amazon 等平台的差异与统一流程,并提供可操作的配置与实现指引,帮助开发者快速集成并扩展新的社交平台。
更新 新增了 Amazon 登录插件的完整实现,采用现代化的 Provider/Service 架构模式,与其他平台保持一致的实现方式。
项目结构
社交登录能力以"插件 Provider + Service"的形式组织在 plugin 目录下,并通过统一的注册中心发现与调度;核心登录协调逻辑集中在 core/service/user/SnsLoginService.php。小程序端通过路由调用后端接口完成授权与绑定。
graph TB
subgraph "插件层"
GProv["GoogleProvider"]
QProv["QqProvider"]
WxProv["WxloginProvider"]
AProv["AmazonProvider"]
end
subgraph "服务层"
GSvc["GoogleService"]
QSvc["QqService"]
WxSvc["WxloginService"]
ASvc["AmazonService"]
SnsCore["SnsLoginService"]
end
subgraph "基础设施"
Reg["ConnectPluginRegistry"]
DB["数据库 user / user_sns"]
Session["Session/状态存储"]
end
Client["浏览器/小程序"] --> Reg
Client --> GProv
Client --> QProv
Client --> WxProv
Client --> AProv
GProv --> GSvc
QProv --> QSvc
WxProv --> WxSvc
AProv --> ASvc
GSvc --> SnsCore
QSvc --> SnsCore
WxSvc --> SnsCore
ASvc --> SnsCore
SnsCore --> DB
SnsCore --> Session
图表来源
- ConnectPluginRegistry.php:25-165
- AmazonProvider.php:16-83
- AmazonService.php:25-220
- GoogleProvider.php:26-99
- GoogleService.php:17-155
- QqProvider.php:13-82
- QqService.php:15-138
- WxloginProvider.php:13-94
- WxloginService.php:18-120
- SnsLoginService.php:35-197
章节来源
- ConnectPluginRegistry.php:25-165
核心组件
- 统一抽象层
- ConnectPluginProviderInterface:定义 start/finish 的统一入口,各平台 Provider 实现该接口。
- ConnectPluginRegistry:自动扫描 manifest.php 并注册 Provider,提供 has()/provider() 查询。
- 平台 Provider 与 Service
- GoogleProvider/GoogleService:基于 Google OAuth2/OIDC,state 校验、code 换 token、Bearer 取用户信息。
- QqProvider/QqService:基于 QQ 互联 SDK,构造授权 URL,回调后获取 openid 与用户信息。
- WxloginProvider/WxloginService:区分公众号/开放平台 UA,按 UA 选择 appid,支持 unionid/openid 模式。
- 新增 AmazonProvider/AmazonService:基于 Amazon Login with Amazon OAuth2.0,实现标准的授权码流程。
- 登录协调器
- SnsLoginService:统一落地策略——已绑定直接登录;未登录且 nobind=true 则自动注册;否则进入绑定流程或跳转绑定页。
章节来源
- AmazonProvider.php:16-83
- AmazonService.php:25-220
- GoogleProvider.php:26-99
- GoogleService.php:17-155
- QqProvider.php:13-82
- QqService.php:15-138
- WxloginProvider.php:13-94
- WxloginService.php:18-120
- SnsLoginService.php:35-197
架构总览
社交登录整体流程分为"发起授权 → 第三方回调 → 令牌交换 → 用户信息拉取 → 账号绑定/登录"。所有平台最终汇聚到 SnsLoginService 进行统一处理。
sequenceDiagram
participant U as "用户"
participant C as "客户端(浏览器/小程序)"
participant P as "Provider(平台入口)"
participant S as "Service(平台服务)"
participant T as "第三方OAuth服务器"
participant L as "SnsLoginService"
participant D as "数据库(user/user_sns)"
U->>C : 点击"使用XX登录"
C->>P : 访问 start()
P->>S : 委托 start()
S->>T : 重定向至授权页(state防CSRF)
T-->>C : 用户授权后回调 finish()
C->>P : 携带 code/state 回调
P->>S : 委托 finish()
S->>T : code 换 access_token
S->>T : 用 token 拉取用户信息
S->>L : resolve(sns, userProfile, loginIdMode, nobind)
L->>D : 查询 user_sns 是否已绑定
alt 已绑定
L-->>C : 写登录态并跳转用户中心
else 未绑定且已登录
L->>D : 写入 user_sns 绑定记录
L-->>C : 跳转绑定成功页
else 未登录且nobind=true
L->>D : 自动注册并写入 user_sns
L-->>C : 写登录态并跳转用户中心
else 未登录且需绑定
L-->>C : 跳转绑定页面(sns_token)
end
图表来源
- AmazonService.php:44-124
- GoogleService.php:64-155
- QqService.php:37-99
- WxloginService.php:40-120
- SnsLoginService.php:57-132
详细组件分析
Amazon 登录(OAuth2.0 授权码流程)
新增 Amazon 登录插件采用标准的 OAuth2.0 授权码流程,与现有平台保持一致的现代化实现。
- 授权发起:生成 state 存入 Session,拼接 Amazon 授权 URL(scope=profile)。
- 回调处理:校验 state,POST 换取 access_token,Bearer 请求用户资料,提取 user_id 作为 openid。
- 统一落地:调用 SnsLoginService.resolve(...),默认允许免绑自动注册(nobind=true)。
flowchart TD
A["start()"] --> B["生成state并保存Session"]
B --> C["拼接Amazon授权URL并重定向"]
C --> D{"finish()收到回调"}
D --> |state不匹配| E["抛出非法操作异常"]
D --> |无code| F["抛出授权失败异常"]
D --> |正常| G["POST换取access_token"]
G --> H["Bearer获取用户资料"]
H --> I["组装sns(openid=user_id, nickname=name)"]
I --> J["SnsLoginService.resolve(..., nobind=true)"]
图表来源
- AmazonService.php:44-124
章节来源
- AmazonProvider.php:16-83
- AmazonService.php:25-220
- manifest.php(Amazon):7-11
Google 登录(OAuth2/OIDC)
- 授权发起:生成 state 存入 Session,拼接 Google 授权 URL(scope=openid email profile)。
- 回调处理:校验 state,POST 换取 access_token,Bearer 请求用户信息,提取 sub 作为 openid。
- 统一落地:调用 SnsLoginService.resolve(...),默认走标准绑定流程(nobind=false)。
flowchart TD
A["start()"] --> B["生成state并保存Session"]
B --> C["拼接Google授权URL并重定向"]
C --> D{"finish()收到回调"}
D --> |state不匹配| E["抛出非法操作异常"]
D --> |无code| F["抛出授权失败异常"]
D --> |正常| G["POST换取access_token"]
G --> H["Bearer获取用户信息"]
H --> I["组装sns(openid=sub, nickname, avatar)"]
I --> J["SnsLoginService.resolve(...)"]
图表来源
- GoogleService.php:64-155
章节来源
- GoogleProvider.php:26-99
- GoogleService.php:17-155
QQ 登录(互联SDK)
- 授权发起:构造 QQ 授权 URL,state 保存在 Session。
- 回调处理:加载 SDK,调用 qq_callback() 获取 accessToken 与 openid,再拉取用户信息。
- 统一落地:组装 sns 数据后交由 SnsLoginService 处理。
章节来源
- QqProvider.php:13-82
- QqService.php:15-138
微信登录(公众号/开放平台)
- 环境识别:根据 UA 判断是否为微信公众号环境,分别选择 open/appid_mp 两套凭据。
- 授权发起:生成 state 并保存,构造对应授权 URL(扫码或网页授权)。
- 回调处理:校验 state,换取 access_token 与 openid,必要时拉取 unionid;按配置决定 loginIdMode(unionid/openid)。
- 统一落地:根据 nobind 配置决定是否允许免绑自动注册。
章节来源
- WxloginProvider.php:13-94
- WxloginService.php:18-120
统一登录协调器(SnsLoginService)
- 优先级策略:
- 若 openid/unionid 已关联本地用户 → 写登录态并跳转用户中心。
- 若当前已登录但未绑定 → 写入 user_sns 绑定记录,返回绑定成功页。
- 若 nobind=true 且未登录 → 自动注册新用户并绑定,写登录态。
- 其他情况 → 将 sns 数据写入 Session,跳转绑定页(带 sns_token)。
flowchart TD
Start(["resolve(sns, userProfile, mode, nobind)"]) --> CheckBind["查询user_sns是否已绑定"]
CheckBind --> |已绑定| Login["写登录态并跳转用户中心"]
CheckBind --> |未绑定| IsLoggedIn{"是否已登录?"}
IsLoggedIn --> |是| Bind["写入user_sns绑定记录"] --> GoProfile["跳转绑定成功页"]
IsLoggedIn --> |否| NobindCheck{"nobind为真?"}
NobindCheck --> |是| AutoReg["自动注册并写入user_sns"] --> AutoLogin["写登录态并跳转用户中心"]
NobindCheck --> |否| ToLink["生成sns_token并跳转绑定页"]
图表来源
- SnsLoginService.php:57-132
章节来源
- SnsLoginService.php:35-197
小程序侧交互
- 小程序通过路由调用后端接口,获取 SNS 列表并触发登录/绑定流程;成功后刷新页面状态。
章节来源
- sns.ts(小程序前端):1-115
依赖关系分析
- 插件发现与装配
- ConnectPluginRegistry 扫描 plugin 目录下的 manifest.php,解析并缓存 Provider 类名,按需实例化。
- 依赖注入
- Provider 仅负责协议适配,具体网络请求与业务编排由 Service 完成。
- Service 依赖 SnsLoginService 进行统一账号绑定与登录态处理。
- 外部依赖
- 各平台 OAuth 服务器(Google、QQ、微信、Amazon 等)。
- 数据库表 user、user_sns 用于用户与第三方身份关联。
classDiagram
class ConnectPluginRegistry {
+discover()
+provider(pluginId)
+has(pluginId) bool
}
class ConnectPluginProviderInterface {
+pluginId() string
+meta() array
+start(request) string
+finish(payload) string
}
class GoogleProvider
class QqProvider
class WxloginProvider
class AmazonProvider
class GoogleService
class QqService
class WxloginService
class AmazonService
class SnsLoginService
ConnectPluginRegistry --> ConnectPluginProviderInterface : "发现并实例化"
GoogleProvider ..|> ConnectPluginProviderInterface
QqProvider ..|> ConnectPluginProviderInterface
WxloginProvider ..|> ConnectPluginProviderInterface
AmazonProvider ..|> ConnectPluginProviderInterface
GoogleProvider --> GoogleService : "委托"
QqProvider --> QqService : "委托"
WxloginProvider --> WxloginService : "委托"
AmazonProvider --> AmazonService : "委托"
GoogleService --> SnsLoginService : "统一落地"
QqService --> SnsLoginService : "统一落地"
WxloginService --> SnsLoginService : "统一落地"
AmazonService --> SnsLoginService : "统一落地"
图表来源
- ConnectPluginRegistry.php:25-165
- AmazonProvider.php:16-83
- AmazonService.php:25-220
- GoogleProvider.php:26-99
- QqProvider.php:13-82
- WxloginProvider.php:13-94
- GoogleService.php:17-155
- QqService.php:15-138
- WxloginService.php:18-120
- SnsLoginService.php:35-197
性能与可扩展性
- 网络请求优化
- 合理设置超时与重试,避免阻塞主流程。
- 对第三方 API 响应做最小化字段解析,减少内存占用。
- 会话与状态
- state 参数短时有效,及时清理,降低会话膨胀风险。
- 敏感信息(token、state)仅在必要生命周期内保留。
- 可扩展性
- 新增平台仅需实现 ConnectPluginProviderInterface,并在 plugin/<platform>/manifest.php 中声明元数据。
- 通过 SnsLoginService 统一对接账号体系,无需改动上层路由与控制器。
故障排查指南
- 常见错误与定位
- state 不匹配:检查 Session 是否被提前销毁或跨域丢失,确认回调地址一致。
- 无法获取 access_token:核对 client_id/secret、redirect_uri 是否与第三方后台一致。
- 无法获取用户信息:检查 scope 是否包含所需字段,Bearer token 是否正确传递。
- 无法获取 unionid:确认微信登录模式配置与授权 scope 是否满足要求。
- 新增 Amazon 登录问题:检查 Amazon Developer Console 中的 Client ID、Client Secret 和 Redirect URIs 配置。
- 日志与调试
- 在服务层关键步骤输出上下文(如 state、code、token、userInfo),便于问题复现。
- 对网络请求结果进行结构化记录,区分 HTTP 错误与业务错误。
章节来源
- AmazonService.php:71-124
- GoogleService.php:97-155
- WxloginService.php:73-120
结论
DouPHP 社交登录插件通过 Provider/Service 分层与 SnsLoginService 统一协调,实现了多平台 OAuth2.0/OIDC 接入的标准化流程。新增的 Amazon 登录插件进一步完善了平台支持,采用与现有平台一致的现代化实现方式。该设计具备良好的可扩展性与安全性基础,配合合理的配置与错误处理,可快速支撑多平台账号体系打通。
附录:开发示例与安全最佳实践
应用注册与密钥配置
- Google
- 在 Google Cloud Console 创建 OAuth 2.0 客户端 ID,添加授权重定向 URI 指向站点回调地址。
- 在插件配置中填写 client_id 与 client_secret。
- QQ
- 在 QQ 互联平台申请 APPID 与 APPKEY,并配置回调地址。
- 微信
- 开放平台(PC 扫码)与公众号(移动端)分别配置对应的 appid 与 appsecret。
- 根据 UA 自动选择凭据,确保授权 scope 正确。
- 新增 Amazon
- 在 Amazon Developer Console 创建 Login with Amazon 应用,获取 Client ID 和 Client Secret。
- 配置 Web Settings 中的 Allowed Origins 和 Allowed Return URLs。
- 在插件配置中填写相应的凭证信息。
章节来源
- AmazonProvider.php:40-63
- GoogleProvider.php:50-78
- QqProvider.php:40-63
- WxloginProvider.php:40-75
授权流程与用户信息获取
- 发起授权:Provider.start() 生成 state 并返回第三方授权 URL。
- 回调处理:Provider.finish() 校验 state,换取 token,拉取用户信息。
- 统一落地:Service 调用 SnsLoginService.resolve(...) 完成绑定或登录。
章节来源
- AmazonService.php:44-124
- GoogleService.php:64-155
- QqService.php:37-99
- WxloginService.php:40-120
- SnsLoginService.php:57-132
账号绑定机制与第三方信息管理
- 已绑定:直接登录并跳转用户中心。
- 未绑定但已登录:写入 user_sns 绑定记录,提示绑定成功。
- 未登录且 nobind=true:自动注册并绑定,写登录态。
- 未登录且需绑定:跳转绑定页,等待用户完成绑定。
章节来源
- SnsLoginService.php:57-132
安全性考虑
- CSRF 防护:使用 state 参数并在回调时严格校验。
- 令牌管理:access_token 仅在服务端临时持有,不落盘;必要时加密存储。
- 会话安全:state 与 sns_token 短期有效,及时清理;限制回调地址白名单。
- 输入校验:对用户昵称等字段进行非法字符过滤,防止注入与 XSS。
章节来源
- AmazonService.php:71-124
- GoogleService.php:97-155
- WxloginService.php:73-120
用户体验优化与多平台兼容
- 一键登录:Google 使用 select_account 提升体验。
- 环境识别:微信按 UA 自动切换授权方式,减少用户操作。
- 错误提示:对授权失败、网络异常等场景给出明确提示与重试引导。
- 新增 Amazon 特色:首次登录自动注册,简化新用户注册流程。
章节来源
- GoogleService.php:64-88
- WxloginService.php:40-67
- AmazonService.php:122-124
平台特性对比
| 平台 | 协议类型 | 唯一标识 | 授权流程 | 自动注册 | 特点 |
|---|---|---|---|---|---|
| OAuth2.0/OIDC | sub (openid) | 标准授权码 | 否 | 支持 OpenID Connect,丰富的用户信息 | |
| 自定义SDK | openid | 授权码 | 否 | 国内用户基数大,SDK成熟 | |
| 微信 | OAuth2.0 | openid/unionid | 授权码 | 可选 | 支持公众号和开放平台双模式 |
| Amazon | OAuth2.0 | user_id (openid) | 标准授权码 | 是 | 国际电商生态,首次登录自动注册 |
新增 Amazon 登录插件的特色在于首次登录时自动注册用户,简化了新用户的注册流程,特别适合面向国际用户的电商平台。