一. 前言
在微信公众号开发中,常常需要使用 h5 页面公众号的授权登录,获取 jscode、openid 等,以便进一步获取用户的开放信息等,和我们系统中的真实用户做绑定。
由于授权登录开发的业务流程,大多都是微信公众号开发的第一步,所以本篇文章将使用最简洁快速的方式实现一个微信公众号 h5 授权获取 openid 流程,并附源码供大家参考!
二. 准备工作
在正式调试之前,确保你的微信公众号已经具备了以下条件:
-
已经是认证的服务号或订阅号(一般为服务号)。
-
在微信公众平台配置了合法的域名。
-
拥有开发者权限,能够访问微信公众平台的接口文档和开发工具。
开发调试阶段
然而,在开发调试,我们可以通过微信公众平台测试账号来进行调试,只需要简单配置即可获取调用微信的接口权限。
通过微信公众平台测试账号,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。
通过微信公众平台测试账号连接配置测试账号进行开发调试!
登录成功后通过以下流程进行简单配置:
- 设置 JS 接口安全域名
- 扫描关注
- 设置授权回调域名
设置完成上面的流程即可以进行开发调试了,如果使用该方式可以调试成功,那么在正式公众号配置正确后也会没有问题。
如果是正式的已经获得权限的公众号,可以在相应的微信公众平台->开发接口管理->基本配置中设置
三. 授权流程
微信 h5 授权登录主要分为以下几个步骤:
1. 引导用户进入授权页面
首先,按照微信公众号的授权流程,构造一个标准 URL 来引导用户进入微信授权页面。该 URL 的格式如下:
js
https://open.weixin.qq.com/connect/oauth2/authorize?
appid=APPID&redirect_uri=REDIRECT_URI&response_type=code
&scope=SCOPE&state=STATE#wechat_redirect
下面对其中的参数含义解释:
-
APPID
是你的公众号的 AppID。 -
REDIRECT_URI
是授权后重定向的回调链接地址,必须要进行 URL 编码,很重要。 -
SCOPE
授权作用域,snsapi_base(静默授权,不弹出授权页面,直接跳转,只能获取用户 openid),snsapi_userinfo(弹出授权页面,可通过 openid 拿到昵称、性别、所在地等信息)。 -
STATE
用于保持请求和回调的状态,授权请求后原样带回给第三方。
在这里,我主要获取用户的 openid,所以使用的是静默授权,即 snsapi_base
作用域。
2. 用户同意授权
用户进入链接后会被重定向到微信授权页面,如果用户同意授权,则会被重定向回你设置的 REDIRECT_URI
,并携带一个 code
参数。
3. 通过 code 换取网页授权 access_token
获取到 code
后,可以调用微信接口,用 code
换取网页授权 access_token。API 如下:
bash
https://api.weixin.qq.com/sns/oauth2/access_token?
appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
其中:
-
APPID
和SECRET
是你的应用 ID 和应用密钥。 -
CODE
上一步中获得的 code。
成功响应示例如下:
json
{
"access_token": "ACCESS_TOKEN",
"expires_in": 7200,
"refresh_token": "REFRESH_TOKEN",
"openid": "OPENID",
"scope": "SCOPE"
}
4. 拉取用户信息(可选)
如果在第一步选择了 snsapi_userinfo 作为 scope,那么可以通过获取到的 access_token
和 openid
来调用接口获取用户的基本信息。API 如下:
ini
https://api.weixin.qq.com/sns/userinfo?
access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
注意:第 3 步和第 4 步为了说明,直接在前端代码中进行了演示,实际开发中为了安全性考虑,应将这两步放在后端进行请求。
四. 可能出现的问题
redirect_uri 参数错误
在开发调试过程中,最常出现的错误就是 redirect_uri
参数错误
出现这个问题一般有两个原因:
redirect_uri
没有使用编码处理,需要使用encodeURIComponent
编码处理
js
getRedirectUri(url) {
url = url || window.location.href
const pos = url.indexOf('?')
if (pos > -1) {
return encodeURIComponent(url.substring(0, pos))
}
console.log(url)
return encodeURIComponent(url)
}
- OAuth2.0 网页授权,授权回调页面域名填写不正确,按照以下方式填写正确即可
一般的,通过以上两步可以解决
redirect_uri
参数错误的问题
五. 注意事项
-
安全性考虑,不要将
secret
等敏感信息暴露在前端代码中,因此前端在获取到 jscode 后可调用后台接口获取 openid 和用户信息。 -
code
的有效期较短,通常为 5 分钟,因此需要尽快使用。 -
正式授权过程中,回调地址必须是已注册的域名下的链接,否则无法成功授权。
-
在开发过程中,建议使用微信公众平台提供的测试账号进行调试,以减少对正式环境的影响。
-
使用 Vue 开发时,建议使用
history
路由模式,避免微信回调链接的参数拼接问题 -
redirect_uri
必须使用encodeURIComponent
进行编码处理
通过上述步骤,你可以顺利地在微信公众号中实现 h5 页面的授权获取到 openid,从而实现用户信息的获取和后续操作。
六. 文档链接
源码
复制以下工具类wxh5.js
到自己项目中,在需要授权的页面中调用即可。
js
import wxh5 from './wxh5'
// 在需要授权的地址,调用方法初始化微信授权,test为appids中的key
wxh5.init('test')
wxh5.js
工具类
js
// 微信公众号appid管理,可加入多个,维护自己的appid
const appids = {
test: 'wx0c5aacb245636f69',
test2: 'wx1bfaa45b867d8b62'
// ... 更多的appid等
}
const scope = 'snsapi_base' // 微信授权scope
const state = 'state' // 微信授权state
// 获取微信授权回调url
export function getRedirectUri(url) {
url = url || window.location.href
const pos = url.indexOf('?')
if (pos > -1) {
return encodeURIComponent(url.substring(0, pos))
}
return encodeURIComponent(url)
}
// 解析url参数
export function getUrlParam(name) {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
var r = window.location.search.substr(1).match(reg)
if (r != null) return unescape(r[2])
return null
}
export default {
// 初始化
init(appType) {
const jscode = getUrlParam('code') // 获取url中的code
console.log('获取到jscode:', jscode)
if (!jscode) {
this.auth(appType)
}
},
// 微信授权
auth(platform) {
const appid = appids[platform]
if (!appid) {
alert('获取 appid 有误,请先维护 appid!')
return
}
const baseUrl = 'https://open.weixin.qq.com/connect/oauth2/authorize'
const url = `${baseUrl}?appid=${appid}&redirect_uri=${getRedirectUri()}&response_type=code&scope=${scope}&state=${state}&connect_redirect=1#wechat_redirect`
window.location.replace(url)
},
// 是否为微信内置浏览器
isWeixin() {
return typeof WeixinJSBridge === 'object' && typeof WeixinJSBridge.invoke === 'function'
},
// 关闭当前微信浏览器窗口
closeWindow() {
if (WeixinJSBridge) {
try {
WeixinJSBridge.call('closeWindow')
} catch (error) {}
}
}
}