跳转至

微信登录服务

微信登录服务 基于微信开放平台的网页扫码登录,对外提供标准的 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:

https://example.com/callback?code=AUTHZ_CODE&state=RANDOM_STATE

在应用后端用授权码换取 access_token:

换取 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 步:获取用户信息

获取用户信息
curl https://nswiki.cn/wechat/oauth/userinfo \
  -H "Authorization: Bearer ACCESS_TOKEN"

返回(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 续期:

刷新 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,旧的不要再用。

撤销授权

撤销 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 严格匹配,防止授权码被劫持到恶意地址。