# 网站应用授权登录

网站应用支持微信扫码登录和微信快捷登录，详细的介绍与接入说明可查看下文。

为了简化用户登录流程，在微信 3.9.11 for Windows 及以上版本与微信 4.0.0 for Mac 及以上版本，用户可使用网站应用快速登录功能。

当网站应用发起微信登录请求时，如果用户此时在 Windows / Mac 设备已经登录了符合要求的微信客户端，且处于非锁定状态，会优先提示用户使用当前微信客户端已登录的账号进行快速登录。

快速登录无需扫码，可直接在 Windows / Mac 设备上进行确认。用户仍可切换其他微信账号或二维码登录。

注意：Chrome 在 142 及以上版本增加了[本地网络访问权限的提示](https://developer.chrome.com/blog/local-network-access?hl=zh-cn)。在该环境下如使用嵌入页面的授权框，浏览器将弹窗提醒用户授权。如授权框非使用下述的 wxLogin.js 引入而是自行嵌入 iframe，则需要明确地在 iframe 增加 `allow="local-network-access"` 属性。

## 1、准备工作

网站应用微信登录是基于 OAuth2.0 协议标准构建的微信 OAuth2.0 授权登录系统。

在进行微信 OAuth2.0 授权登录接入之前，在微信开放平台注册开发者账号，并拥有一个已审核通过的网站应用，并获得相应的 `AppID` 和 `AppSecret`，申请微信登录且通过审核后，可开始接入流程。

## 2、授权流程说明

微信 OAuth2.0 授权登录让微信用户使用微信身份安全登录第三方应用或网站，在微信用户授权登录已接入微信 OAuth2.0 的第三方应用后，第三方可以获取到用户的接口调用凭证（`access_token`），通过 `access_token` 可以进行微信开放平台授权关系接口调用，从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。

微信 OAuth2.0 授权登录目前支持 `authorization_code` 模式，适用于拥有 server 端的应用授权。该模式整体流程为：

1）第三方发起微信授权登录请求，微信用户允许授权第三方应用后，微信会拉起应用或重定向到第三方网站，并且带上授权临时票据 `code` 参数。

2）通过 `code` 参数加上 `AppID` 和 `AppSecret` 等，通过 API 换取 `access_token`。

3）通过 `access_token` 进行接口调用，获取用户基本数据资源或帮助用户实现基本操作。

获取 `access_token` 时序图：

![](https://res.wx.qq.com/op_res/D0wkkHSbtC6VUSHX4WsjP5ssg5mdnEmXO8NGVGF34dxS9N1WCcq6wvquR4K_Hcut)

### 第一步：请求 CODE

第三方使用网站应用授权登录前请注意已获取相应网页授权作用域（scope=snsapi_login），则可以通过在 PC 端打开以下链接：

```
https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
```

若提示「该链接无法访问」，请检查参数是否填写错误，如 `redirect_uri` 的域名与审核时填写的授权域名不一致或 scope 不为 `snsapi_login`。

**参数说明**

| 参数 | 是否必须 | 说明 |
| --- | --- | --- |
| appid | 是 | 应用唯一标识 |
| redirect_uri | 是 | 请使用 urlEncode 对链接进行处理 |
| response_type | 是 | 填 `code` |
| scope | 是 | 应用授权作用域，拥有多个作用域用逗号（,）分隔，网页应用目前仅填写 `snsapi_login` |
| state | 否 | 用于保持请求和回调的状态，授权请求后原样带回给第三方。该参数可用于防止 CSRF 攻击（跨站请求伪造攻击），建议第三方带上该参数，可设置为简单的随机数加 session 进行校验 |
| lang | 否 | 界面语言，支持 cn（中文简体）与 en（英文），默认为 cn |

**返回说明**

用户允许授权后，将会重定向到 `redirect_uri` 的网址上，并且带上 `code` 和 `state` 参数：

```
redirect_uri?code=CODE&state=STATE
```

若用户禁止授权，则不会发生重定向。

**请求示例**

登录一号店网站应用 `https://test.yhd.com/wechat/login.do`，打开后，一号店会生成 state 参数，跳转到：

```
https://open.weixin.qq.com/connect/qrconnect?appid=wxbdc5610cc59c1631&redirect_uri=https%3A%2F%2Fpassport.yhd.com%2Fwechat%2Fcallback.do&response_type=code&scope=snsapi_login&state=3d6be0a4035d839573b04816624a415e#wechat_redirect
```

微信用户使用微信扫描二维码并且确认登录后，PC 端会跳转到：

```
https://test.yhd.com/wechat/callback.do?code=CODE&state=3d6be0a40sssssxxxxx6624a415e
```

**将微信登录二维码内嵌到自己页面**

为了满足网站更定制化的需求，还提供了第二种获取 `code` 的方式，支持网站将微信登录二维码内嵌到自己页面中，用户使用微信扫码授权后通过 JS 将 `code` 返回给网站。

JS 微信登录主要用途：网站希望用户在网站内就能完成登录，无需跳转到微信域下登录后再返回，提升微信登录的流畅性与成功率。网站内嵌二维码微信登录 JS 实现办法：

步骤 1：在页面中先引入如下 JS 文件（支持 https）：

```
http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
```

步骤 2：在需要使用微信登录的地方实例以下 JS 对象：

```javascript
var obj = new WxLogin({
  self_redirect: true,
  id: "login_container",
  appid: "",
  scope: "",
  redirect_uri: "",
  state: "",
  style: "",
  href: "",
  onReady: function(isReady) {
    console.log(isReady);
  }
});
```

**参数说明**

| 参数 | 是否必须 | 说明 |
| --- | --- | --- |
| self_redirect | 否 | true：手机点击确认登录后可以在 iframe 内跳转到 redirect_uri，false：手机点击确认登录后可以在 top window 跳转到 redirect_uri。默认为 false。 |
| id | 是 | 第三方页面显示二维码的容器 id |
| appid | 是 | 应用唯一标识，在微信开放平台提交应用审核通过后获得 |
| scope | 是 | 应用授权作用域，拥有多个作用域用逗号（,）分隔，网页应用目前仅填写 `snsapi_login` 即可 |
| redirect_uri | 是 | 重定向地址，需要进行 UrlEncode |
| state | 否 | 用于保持请求和回调的状态，授权请求后原样带回给第三方。该参数可用于防止 CSRF 攻击（跨站请求伪造攻击），建议第三方带上该参数，可设置为简单的随机数加 session 进行校验 |
| style | 否 | 提供 "black"、"white" 可选，默认为黑色文字描述。详见文档底部 FAQ |
| href | 否 | 自定义样式链接，第三方可根据实际需求覆盖默认样式，stylelite 不为 1 时有效。详见文档底部 FAQ |
| stylelite | 否 | 切换二维码登录样式，值为 1 时二维码登录将切换到新样式。详见文档底部 FAQ。 |
| fast_login | 否 | 启用或禁用快速登录功能，值为 0 时将禁用快速登录，如发现参数不生效可检查 redirect_uri 是否已经正确 encode。 |
| color_scheme | 否 | 支持切换 light 或 dark 主题，值为 "light" 表示仅支持 light 主题，值为 "dark" 时表示仅支持 dark 主题，值为 "auto" 时表示跟随系统主题，不使用该参数将保持浏览器默认主题。 |
| onReady | 否 | iframe 页面是否加载成功的回调，isReady 为 true 表示加载成功 |
| onQRcodeReady | 否 | 二维码加载完成的回调 |

### 第二步：通过 code 获取 access_token

通过 `code` 获取 `access_token`：

```
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
```

**参数说明**

| 参数 | 是否必须 | 说明 |
| --- | --- | --- |
| appid | 是 | 应用唯一标识，在微信开放平台提交应用审核通过后获得 |
| secret | 是 | 应用密钥 `AppSecret`，在微信开放平台提交应用审核通过后获得 |
| code | 是 | 填写第一步获取的 `code` 参数 |
| grant_type | 是 | 填 `authorization_code` |

**返回说明**

正确的返回：

```json
{
  "access_token": "ACCESS_TOKEN",
  "expires_in": 7200,
  "refresh_token": "REFRESH_TOKEN",
  "openid": "OPENID",
  "scope": "SCOPE",
  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
```

| 参数 | 说明 |
| --- | --- |
| access_token | 接口调用凭证 |
| expires_in | `access_token` 接口调用凭证超时时间，单位（秒） |
| refresh_token | 用户刷新 `access_token` |
| openid | 授权用户唯一标识 |
| scope | 用户授权的作用域，使用逗号（,）分隔 |
| unionid | 当且仅当该网站应用已获得该用户的 userinfo 授权时，才会出现该字段 |

错误返回样例：

```json
{"errcode":40029,"errmsg":"invalid code"}
```

**刷新 access_token 有效期**

`access_token` 是调用授权关系接口的调用凭证，由于 `access_token` 有效期（目前为 2 个小时）较短，当 `access_token` 超时后，可以使用 `refresh_token` 进行刷新，`access_token` 刷新结果有两种：

1）若 `access_token` 已超时，那么进行 `refresh_token` 会获取一个新的 `access_token`，新的超时时间。

2）若 `access_token` 未超时，那么进行 `refresh_token` 不会改变 `access_token`，但超时时间会刷新，相当于续期 `access_token`。

`refresh_token` 拥有较长的有效期（30 天），当 `refresh_token` 失效的后，需要用户重新授权。

**请求方法**

获取第一步的 `code` 后，请求以下链接进行 `refresh_token`：

```
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
```

**参数说明**

| 参数 | 是否必须 | 说明 |
| --- | --- | --- |
| appid | 是 | 应用唯一标识 |
| grant_type | 是 | 填 `refresh_token` |
| refresh_token | 是 | 填写通过 `access_token` 获取到的 `refresh_token` 参数 |

**返回说明**

正确的返回：

```json
{
  "access_token": "ACCESS_TOKEN",
  "expires_in": 7200,
  "refresh_token": "REFRESH_TOKEN",
  "openid": "OPENID",
  "scope": "SCOPE"
}
```

| 参数 | 说明 |
| --- | --- |
| access_token | 接口调用凭证 |
| expires_in | `access_token` 接口调用凭证超时时间，单位（秒） |
| refresh_token | 用户刷新 `access_token` |
| openid | 授权用户唯一标识 |
| scope | 用户授权的作用域，使用逗号（,）分隔 |

错误返回样例：

```json
{"errcode":40030,"errmsg":"invalid refresh_token"}
```

**注意：**

1）`AppSecret` 是应用接口使用密钥，泄漏后将可能导致应用数据泄漏、应用的用户数据泄漏等高风险后果；存储在客户端，极有可能被恶意窃取（如反编译获取 `AppSecret`）。

2）`access_token` 为用户授权第三方应用发起接口调用的凭证（相当于用户登录态），存储在客户端，可能出现恶意获取 `access_token` 后导致的用户数据泄漏、用户微信相关接口功能被恶意发起等行为。

3）`refresh_token` 为用户授权第三方应用的长效凭证，仅用于刷新 `access_token`，但泄漏后相当于 `access_token` 泄漏，风险同上。

4）如无特别业务需求，建议开发者自行管理业务登录态并合理设置过期时间，减少用户重新授权登录次数，优化用户体验。

**建议将 `AppSecret`、用户数据（如 `access_token`）放在 App 云端服务器，由云端中转接口调用请求。**

### 第三步：通过 access_token 调用接口

获取 `access_token` 后，进行接口调用，有以下前提：

1）`access_token` 有效且未超时。

2）微信用户已授权给第三方应用账号相应接口作用域（scope）。

对于接口作用域（scope），能调用的接口有以下：

| 授权作用域（scope） | 接口 | 接口说明 |
| --- | --- | --- |
| snsapi_base | /sns/oauth2/access_token | 通过 code 换取 access_token、refresh_token 和已授权 scope |
| snsapi_base | /sns/oauth2/refresh_token | 刷新或续期 access_token 使用 |
| snsapi_base | /sns/auth | 检查 access_token 有效性 |
| snsapi_userinfo | /sns/userinfo | 获取用户个人信息 |

其中 `snsapi_base` 属于基础接口，若应用已拥有其它 scope 权限，则默认拥有 `snsapi_base` 的权限。使用 `snsapi_base` 可以让移动端网页授权绕过跳转授权登录页请求用户授权的动作，直接跳转第三方网页带上授权临时票据（`code`），但会使得用户已授权作用域（scope）仅为 `snsapi_base`，从而导致无法获取到需要用户授权才允许获得的数据和基础功能。

接口调用方法可查阅[微信授权关系接口调用指南](/doc/oplatform/Website_App/WeChat_Login/Authorized_Interface_Calling_UnionID.md)。

## 3、F.A.Q

**1. 什么是授权临时票据（code）？**

答：第三方通过 `code` 进行获取 `access_token` 的时候需要用到，`code` 的超时时间为 10 分钟，一个 `code` 只能成功换取一次 `access_token` 即失效。`code` 的临时性和一次保障了微信授权登录的安全性。第三方可通过使用 https 和 state 参数，进一步加强自身授权登录的安全性。

**2. 什么是授权作用域（scope）？**

答：授权作用域（scope）代表用户授权给第三方的接口权限，第三方应用需要向微信开放平台申请使用相应 scope 的权限后，使用文档所述方式让用户进行授权，经过用户授权，获取到相应 `access_token` 后方可对接口进行调用。

**3. 网站内嵌二维码微信登录 JS 代码中 style 字段作用？**

答：第三方页面颜色风格可能为浅色调或者深色调，若第三方页面为浅色背景，style 字段应提供 "black" 值（或者不提供，black 为默认值），则对应的微信登录文字样式为黑色。相关效果如下：

![](https://res.wx.qq.com/op_res/QWBllsRJkSzl2bX590fsHHL89vhVeAcck2qLZ8pvPYN03imZryim1Bil6dAfs_SK)
![](https://res.wx.qq.com/op_res/13w7hjq0ZVNMNLcn91w9Cw0TZ7CtCsSwGW5mZ9GbuzzCzT0-nV5CCQ-BzJZDAtEU)

若提供 "white" 值，则对应的文字描述将显示为白色，适合深色背景。相关效果如下：

![](https://res.wx.qq.com/op_res/WAvW71FoNpu-NzpZf_bpCRiS2ZgO6vANtVp0d6ilxP-gkko9QkyOjoxjmMxC8Gll)
![](https://res.wx.qq.com/op_res/iDyHm_ENEu4jVbXwVZoZKeEw36RA0dafqFGU-v-xTBCFc_sfb64wPxJlHPFDvdD9)

**4. 网站内嵌二维码微信登录 JS 代码中 href 字段作用？**

答：如果第三方觉得微信团队提供的默认样式与自己的页面样式不匹配，可以自己提供样式文件来覆盖默认样式。举个例子，如第三方觉得默认二维码过大，可以提供相关 CSS 样式文件，并把链接地址填入 href 字段：

```css
.impowerBox .qrcode {width: 200px;}
.impowerBox .title {display: none;}
.impowerBox .info {width: 200px;}
.status_icon {display: none}
.impowerBox .status {text-align: center;}
```

相关效果如下：

![](https://res.wx.qq.com/op_res/fW6MmqxGxJAzfluM9TDV58JifCanyliNg-y026kpPVVrkfEAACN6b021LbOZD3pa)
![](https://res.wx.qq.com/op_res/LebglCIrjHSPDMK7mGrkR1ihb1o4jyDA5vSOB7X_3NPwBq5f5bXkocVhPkQHJVpD)

**5. 网站内嵌二维码微信登录 JS 代码中的 stylelite 字段作用？**

答：平台对微信授权登录进行了 UI 改版，为了保证不影响现有的微信扫码登录功能，提供 stylelite 参数用于自行选择新旧 UI。默认为旧 UI，当 stylelite 为 1 时将切换到新 UI，同时通过 href 参数引入的自定义样式将会失效，为确保显示效果，建议扫码区域至少预留 220px * 220px。

新版二维码样式效果如下：

![扫码初始化](https://res.wx.qq.com/op_res/pyLhLxcJ3gCXERdVwA5rOInd2K0pUX2IKRiO6ubvtHxImhPUf-0v4LtiNlWdY9RMaiIeqburapnCifAnDmVkLA)
![扫码结果](https://res.wx.qq.com/op_res/pyLhLxcJ3gCXERdVwA5rOAnw6Pv-PirRua-RdljlaUfIiO7XcQ9eSkJBdUqMyY48bbIllWupqpF2b5kJTFzqvg)
![二维码失效](https://res.wx.qq.com/op_res/pyLhLxcJ3gCXERdVwA5rOKem_Br0fZfwu6rmNPPpw2XGgKdAmFKGBltQJ2RknmSp5xz2-wPmeKFo_u3-5t8KGA)
