微信登录 SSO¶
微信登陆 SSO 是 NS WIKI 的一项登录服务,基于微信开放平台的网页扫码登录,对外提供标准的 OAuth2 授权码(Authorization Code)流程。
在shipengliang大佬的帮助下注册得到的微信网页登陆能力。
用户用微信扫码授权后,第三方应用即可获取其微信昵称与头像,无需各自维护账号密码体系。
服务地址:https://nswiki.cn/wechat
这是什么¶
- 对用户:一个微信扫码登录入口。
- 对开发者:一个自建的 OAuth2 / OpenID Connect 风格的认证提供方(Identity Provider),应用通过标准流程换取用户身份信息。
支持的能力:
- 微信扫码授权登录
- 标准 OAuth2 授权码流程(
authorization_code) -
refresh_token刷新与轮换 - OpenID Connect 风格的 UserInfo 端点
- 「记住本设备」快速登录(60 天内免扫码)
- 撤销授权(revoke)
接入流程概览¶
sequenceDiagram
autonumber
participant U as 用户
participant App as 第三方应用
participant SSO as NSWIKI SSO
participant WX as 微信开放平台
U->>App: 点击「微信登录」
App->>SSO: 重定向到 /oauth/authorize
SSO->>U: 展示微信扫码二维码
U->>WX: 微信扫码并确认
WX->>SSO: 回调 /oauth/callback(携带微信 code)
SSO->>U: 展示授权确认页(是否授权给该应用)
U->>SSO: 点击「同意」
SSO->>App: 重定向回 redirect_uri(携带授权码 code)
App->>SSO: POST /oauth/token(code + client_secret)
SSO-->>App: 返回 access_token + refresh_token
App->>SSO: GET /oauth/userinfo(Bearer access_token)
SSO-->>App: 返回用户昵称、头像
快速开始¶
第 1 步:注册应用¶
联系 NS WIKI 管理员注册你的应用,获取 client_id 和 client_secret,并登记一个固定的 redirect_uri(回调地址)。
redirect_uri 必须完全一致
授权时传入的 redirect_uri 会与注册值做严格相等匹配,不一致将直接拒绝。
请连同协议(https://)、端口、路径一起登记准确。
第 2 步:引导用户到授权页¶
将用户浏览器重定向到:
https://nswiki.cn/wechat/oauth/authorize
?client_id=YOUR_CLIENT_ID
&redirect_uri=https://example.com/callback
&response_type=code
&scope=profile
&state=RANDOM_STATE
| 参数 | 必填 | 说明 |
|---|---|---|
client_id |
是 | 注册应用时发放的 ID |
redirect_uri |
是 | 回调地址,须与注册值完全一致 |
response_type |
是 | 固定为 code |
scope |
是 | 固定为 profile |
state |
否 | 防 CSRF 的随机串,会原样带回回调地址 |
务必校验 state
生成一个随机 state 并在回调时校验它是否一致,可防止跨站请求伪造(CSRF)攻击。
第 3 步:用授权码换 token¶
用户同意授权后,SSO 会重定向回你的 redirect_uri 并附带 code 与 state:
在应用后端用授权码换取 access_token:
curl -X POST https://nswiki.cn/wechat/oauth/token \
-d "grant_type=authorization_code" \
-d "code=AUTHZ_CODE" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "redirect_uri=https://example.com/callback"
返回:
{
"access_token": "9f3c...",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "a71e...",
"scope": "profile"
}
client_secret 只能放在后端
换 token 需要 client_secret,绝不能出现在前端代码或浏览器中。
授权码有效期仅 10 分钟且只能使用一次。
第 4 步:获取用户信息¶
返回(OpenID Connect UserInfo 风格):
{
"sub": "oXXXX...", // 用户唯一标识(openid)
"nickname": "微信昵称", // 微信昵称
"picture": "https://..." // 头像 URL
}
API 端点¶
| 方法 | 端点 | 说明 |
|---|---|---|
GET |
/wechat/ |
服务主页与 API 简介 |
GET |
/wechat/oauth/authorize |
授权入口(扫码登录页) |
POST |
/wechat/oauth/token |
授权码换 token / 刷新 token |
GET |
/wechat/oauth/userinfo |
获取当前授权用户信息 |
POST |
/wechat/oauth/revoke |
撤销 access_token 或 refresh_token |
GET |
/wechat/logout |
退出登录(清除快速登录凭证) |
刷新 token¶
access_token 有效期 2 小时。过期后用 refresh_token 续期:
curl -X POST https://nswiki.cn/wechat/oauth/token \
-d "grant_type=refresh_token" \
-d "refresh_token=REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
refresh_token 会轮换
每次刷新都会签发新的 refresh_token 并使旧的立即失效。
请保存每次返回的最新 refresh_token,旧的不要再用。
撤销授权¶
curl -X POST https://nswiki.cn/wechat/oauth/revoke \
-d "token=ACCESS_OR_REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
有效期一览¶
| 凭证 | 默认有效期 |
|---|---|
授权码 code |
10 分钟(一次性) |
access_token |
2 小时 |
refresh_token |
30 天(每次刷新轮换) |
| 快速登录凭证 | 60 天 |
错误码¶
| error | 出现位置 | 说明 |
|---|---|---|
invalid_client |
token / revoke | client_id 或 client_secret 错误 |
invalid_grant |
token | 授权码或 refresh_token 无效 / 已过期 / 已使用 |
unsupported_grant_type |
token | grant_type 不是 authorization_code 或 refresh_token |
invalid_request |
userinfo | 缺少 Authorization: Bearer 头 |
invalid_token |
userinfo | access_token 无效或已过期 |
access_denied |
授权回调 | 用户在确认页点击了「拒绝」 |
快速登录(记住本设备)¶
用户在授权确认页勾选「记住本设备」后,SSO 会种下有效期 60 天的快速登录凭证。 此后同一设备再次进入授权页时,可一键登录、无需再次扫码,直到凭证过期或用户主动退出 / 清除。
安全说明¶
- 所有令牌在数据库中只存 SHA-256 哈希,不存明文。
- 授权回调使用
state做 CSRF 校验。 - 授权确认通过短期签名凭证完成,避免微信跳转导致会话丢失。
redirect_uri严格匹配,防止授权码被劫持到恶意地址。