微信登录服务¶
微信登录服务 基于微信开放平台的网页扫码登录,对外提供标准的 OAuth2 授权码(Authorization Code)流程。
在 时鹏亮 大佬的帮助下注册得到微信网页登陆能力。
这是什么¶
- 对用户:一个微信扫码登录入口。
- 对开发者:一个自建的 OAuth2 / OpenID Connect 风格的认证提供方(Identity Provider),应用通过标准流程换取用户身份信息。
支持的能力:
- 微信扫码授权登录
- 标准 OAuth2 授权码流程(
authorization_code) - APP 扫码登录(设备授权流程,全程不出现你的域名)
-
refresh_token刷新与轮换 - OpenID Connect 风格的 UserInfo 端点
- 撤销授权(revoke)
接入流程概览¶
sequenceDiagram
autonumber
participant U as 用户
participant App as 第三方应用
participant SSO as NSWIKI微信登录服务
participant WX as 微信开放平台
U->>App: 点击「微信登录」
App->>SSO: 重定向到 /oauth/authorize
SSO->>U: 展示扫码登录页(二维码 + 应用信息)
U->>WX: 微信扫码并确认(确认即视为同意授权)
WX->>SSO: 回调 /oauth/callback(携带微信 code)
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微信登录管理页面 https://nswiki.cn/wechat/a/ ,用微信扫描登陆后创建应用。
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
}
APP 扫码登录(设备授权流程)¶
标准流程需要把用户的浏览器重定向回你的 redirect_uri。如果你的产品是一个 APP——没有网页、或者不希望用户看到你的网址——可以改用设备授权流程:
- APP 里只显示一个二维码,用户用微信扫码;
- 微信回调只经过 NSWIKI 的服务器,全程不出现你的域名;
- 你的服务器轮询获取结果,拿到的 token 与标准流程完全相同。
sequenceDiagram
autonumber
participant U as 用户
participant App as 你的APP
participant Srv as 你的服务器
participant SSO as NSWIKI微信登录服务
participant WX as 微信
Srv->>SSO: POST /oauth/device/code(client_id + client_secret)
SSO-->>Srv: 返回 ticket + 二维码内容 qr_content(附图片地址 qr_image)
Srv->>App: 把二维码交给 APP
App->>U: 显示二维码
U->>WX: 微信扫码并确认
WX-->>SSO: 服务端长轮询取回扫码结果
SSO-->>U: 手机显示「登录成功,请返回 APP」
loop 每 2 秒一次,直到成功或过期
Srv->>SSO: POST /oauth/device/token(ticket)
SSO-->>Srv: authorization_pending / 成功后返回 token
end
Srv->>SSO: GET /oauth/userinfo(Bearer access_token)
redirect_uri 填占位地址即可
设备流程不会跳回你的服务器,注册应用时 redirect_uri 没有实际用途,填一个占位 HTTPS 地址(如 https://example.invalid/callback)即可。
第 1 步:创建登录票据¶
用户打开 APP 的登录页时,你的服务器调用:
curl -X POST https://nswiki.cn/wechat/oauth/device/code \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
返回:
{
"ticket": "c4d2...",
"qr_content": "https://open.weixin.qq.com/connect/confirm?uuid=...",
"qr_image": "https://open.weixin.qq.com/connect/qrcode/...",
"expires_in": 300,
"interval": 2
}
把 qr_content 发给 APP,用任意二维码库显示成二维码;也可以直接显示 qr_image(微信官方的二维码图片地址,连二维码库都可以不用)。这是微信原生登录二维码,用户微信扫码后会直接弹出登录确认页,不会出现中转页。ticket 留在你的服务器,不要发给 APP。
第 2 步:轮询登录结果¶
你的服务器每 interval 秒(默认 2 秒)轮询一次:
curl -X POST https://nswiki.cn/wechat/oauth/device/token \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "ticket=TICKET"
用户还没扫码时返回 {"error": "authorization_pending"},继续轮询即可。扫码成功后返回与标准流程完全相同的 token:
{
"access_token": "9f3c...",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "a71e...",
"scope": "profile"
}
第 3 步:获取用户信息¶
与标准流程相同:用 access_token 调 GET /wechat/oauth/userinfo。之后的刷新、撤销也完全一样。
使用注意
- 二维码 5 分钟过期,过期后重新调一次第 1 步换一张即可。
- 轮询间隔不要小于
interval:太快会收到slow_down,要求的间隔还会变长。 - 每个
ticket只能成功兑换一次 token。 - 用户在微信里看到的确认页和「登录成功」页都在 nswiki.cn 上,你的域名不会出现。
- 谁扫码就以谁的身份登录,请把登录结果和 APP 自己的会话绑定好。
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 |
POST |
/wechat/oauth/device/code |
设备流程:创建登录票据,返回二维码链接 |
GET |
/wechat/oauth/device/callback |
设备流程:微信扫码回调(仅 SSO 内部使用) |
POST |
/wechat/oauth/device/token |
设备流程:轮询登录结果,签发 token |
GET |
/wechat/logout |
退出登录(清理历史 Cookie) |
刷新 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 分钟(一次性) |
设备票据 ticket |
5 分钟(一次性) |
access_token |
2 小时 |
refresh_token |
30 天(每次刷新轮换) |
错误码¶
| error | 出现位置 | 说明 |
|---|---|---|
invalid_client |
token / revoke / device | client_id 或 client_secret 错误 |
invalid_grant |
token / device/token | 授权码、refresh_token 或 ticket 无效 / 已过期 / 已使用 |
unsupported_grant_type |
token | grant_type 不是 authorization_code 或 refresh_token |
authorization_pending |
device/token | 用户还未扫码,继续轮询 |
slow_down |
device/token | 轮询过快,按返回的 interval 放慢 |
expired_token |
device/token | 票据已过期,重新创建 |
invalid_request |
userinfo | 缺少 Authorization: Bearer 头 |
invalid_token |
userinfo | access_token 无效或已过期 |
安全说明¶
- 所有令牌与设备票据在数据库中只存 SHA-256 哈希,不存明文。
- 授权回调使用
state做 CSRF 校验。 - 用户在微信中确认扫码即视为同意授权;授权上下文由服务端会话(session)维护,无需单独的确认页。
redirect_uri严格匹配,防止授权码被劫持到恶意地址。