# 公众号H5页面接入微信登录流程 **Repository Path**: hankaiinterspace/h5_weixin ## Basic Information - **Project Name**: 公众号H5页面接入微信登录流程 - **Description**: 手机公众号页面接入微信授权功能,获取用户openid,头像,昵称 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 8 - **Created**: 2022-07-29 - **Last Updated**: 2022-07-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 公众号H5页面接入微信登录流程 ## 源码地址 https://gitee.com/szxio/h5_weixin ## 起步 首先创建一个项目,我们采用uni-app来作为我们的前端框架 ### [环境安装](https://uniapp.dcloud.io/quickstart-cli?id=环境安装) 全局安装`vue-cli` ```shell npm install -g @vue/cli ``` ### [创建uni-app](https://uniapp.dcloud.io/quickstart-cli?id=创建uni-app) **使用正式版**(对应HBuilderX最新正式版) ```shell vue create -p dcloudio/uni-preset-vue my-project ``` 在安装过程中选择默认版本即可 ### 启动 安装完成后按照提示进入我们的项目根目录下执行启动命令 ```shell npm run serve ``` 启动成功图 ![](https://gitee.com/szxio/h5_weixin/raw/master/src/static/README/1.png) ## 申请测试号 ### 官方文档 [文档地址](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html) ### 申请测试公众号 这里我们本地学习,所以可以申请一个测试哈,方便我们快速了解微信相关配置。在实际开发中我们会将我们的网站配置在真正的公众号中。 1.首先登录[微信公众平台](https://mp.weixin.qq.com/),选择一个公众号登录,第一次登录时可能没有公众号,我们可以[申请注册](https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN&token=)一个订阅号即可。 登录进来后点击下图标示菜单可以申请一个测试号 ![](https://gitee.com/szxio/h5_weixin/raw/master/src/static/README/2.png) 点击之后我要求我们登录,我们扫码登录一下即可,然后可以看到如下界面 ![](https://gitee.com/szxio/h5_weixin/raw/master/src/static/README/3.png) 这里可以看到我们公众号的`appID`和`appsecret`。另外由于我之前设置过相关配置,所以这里的 `接口配置信息` 和 J`S接口安全域名` 有内容,第一次申请的没有,不过不影响我们本次教程的后续开发。当我们有需要时可以重新在这个页面中去设置相关接口信息 ### 配置授权回调页面域名 在测试号管理页面往下滑可以看到下面的配置项 ![](https://gitee.com/szxio/h5_weixin/raw/master/src/static/README/4.png) 设置我们项目的启动地址,由于是测试号,所以这里可以配置IP地址 **注意:测试号可以配置ip地址,正式号只能配置域名** ![](https://gitee.com/szxio/h5_weixin/raw/master/src/static/README/5.png) ## 给测试号配置菜单 ### 安装axiox ```shell npm install axios --save ``` ### 获取AccessToken 调用如下地址即可获取`AccessToken` ```http GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET ``` [官方文档地址](https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html) 请求如下接口获取Access token,这个Access token有7200秒的有效期,并且接口每天限制2000次请求,所以一般由后端去请求该接口并保存起来,并且设置定时刷新。但是由于现在学习阶段,所以我们前端可以直接请求 新建 `src\util\getTonken.js` 文件,编写如下代码 ```js import http from "axios" const APPID = "这里替换成测试号的APPID" const APPSECRET = "这里替换成测试号的APPSECRET" // 更新tonken function updateToken() { return new Promise((resolve, reject) => { http.get(`/weixin/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`).then(res => { resolve(res.data.access_token) }).catch(err => { reject(err) }) }) } // 获取Tonken export function getToKen() { return new Promise(async (resolve, reject) => { // 从缓存中读取token let stroagetoken = uni.getStorageSync('accessToken') // 如果缓存中有token,则直接返回缓存中的token if (stroagetoken) { console.log('缓存获取的token'); // 返回结果 resolve(stroagetoken) } else { // 如果缓存没有token,则走接口重新获取新的token let token = await updateToken() // 存入到缓存中 uni.setStorageSync('accessToken', token) // 设置定时任务,每隔7000秒更新一次tonken setInterval(async () => { // 获取新的token let token = await updateToken() // 存入到缓存中 uni.setStorageSync('accessToken', token) }, 7000000); console.log('接口获取的token'); // 返回结果 resolve(token) } }) } ``` ### 请求微信地址的跨域问题 上面的代码中可以看到请求地址是以 `/weixin` 开头的,这是因为我们在前端直接请求 `https://api.weixin.qq.com` 会产生跨域问题,所以我配置了前端代理,配置方式如下: 首先在项目根目录新建 `vue.config.js` 文件,编写如下代码 ```js module.exports = { publicPath: "./", devServer: { disableHostCheck: true, //禁用主机检查 proxy: { "/weixin": { target: "https://api.weixin.qq.com/", ws: true, secure: true, // 使用的是http协议则设置为false,https协议则设置为true changOrigin: true, //开启代理 pathRewrite: { "^/weixin": "", }, } }, }, }; ``` 然后重启项目,之后在发送请求时,用 `/weixin` 开头去发送请求,则node会自动帮我们吧请求地址代理到 `https://api.weixin.qq.com/` ,从而解决跨域问题 ### 创建菜单 接口地址 ```http POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN ``` [接口参数](https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.html)见官网文档 下面代码即可为测试号创建一个普通菜单 ```js const ACCESS_TOKEN = uni.getStorageSync("accessToken"); const menuObj = { button: [ { type: "view", name: "测试项目", url: "http://192.168.60.230:8080/", }, ], }; // 创建菜单 http.post(`/weixin/cgi-bin/menu/create?access_token=${ACCESS_TOKEN}`, menuObj).then((res) => { console.log(res, "创建菜单"); }); ``` 代码执行后,我们扫描测试号的二维码,即可看到配置的菜单。这里要保证我们的手机和电脑在同一个局域网下,通俗点就是连着同一个WiFi,这样我们才能在手机端点击菜单进入到我们的项目中 ## 微信网页授权 ### 授权步骤 - [第一步:用户同意授权,获取code](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#0) - [第二步:通过code换取网页授权access_token](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#1) - [第三步:刷新access_token(如果需要)](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#2) - [第四步:拉取用户信息(需scope为 snsapi_userinfo)](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#3) - [附:检验授权凭证(access_token)是否有效](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#4) ### 引导关注者开发授权页面 我们可以让用户跳转到授权页面,如果用户同意授权,页面将跳转至 `redirect_uri/?code=CODE&state=STATE。` 授权地址 ```http https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect ``` 参数说明 | 参数 | 是否必须 | 说明 | | :--------------- | :------- | :----------------------------------------------------------- | | appid | 是 | 公众号的唯一标识 | | redirect_uri | 是 | 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理 | | response_type | 是 | 返回类型,请填写code | | scope | 是 | 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 ) | | state | 否 | 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节 | | #wechat_redirect | 是 | 无论直接打开还是做页面302重定向时候,必须带此参数 | 开始编码 ```html ``` ```js data() { return { homeUrl:"http://192.168.60.230:8080/", }; }, methods: { // 点击授权按钮 getUserInfo() { // 获取当前页面地址作为回调地址,并且对地址进行urlEncode处理 let local = encodeURIComponent(this.homeUrl); // 获取公众号appid let appid = "wx2188729b190d357d"; // 跳转到授权页面 window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid + "&redirect_uri=" + local + "&response_type=code&scope=snsapi_base&state=1#wechat_redirect"; }, } ``` 点击按钮跳转到授权页面,然后微信会将参数拼接到回调地址中,我们从地址中获取code参数来获取网页授权的 `access token` ![](https://gitee.com/szxio/h5_weixin/raw/master/src/static/README/7.png) ### 通过路径上的code获取网页授权token 获取token的接口地址 ```http GET https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code ``` 首先我们封装一个获取路径参数的方法 ```js getUrlCode(name) { return ( decodeURIComponent( (new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec( location.href ) || [, ""])[1].replace(/\+/g, "%20") ) || null ); } ``` 然后再添加一个根据`code`获取`token`的方法,这里的`APPID`和`APPSECRET`放在了`data`中,这里可以优化成写一个配置文件,页面可以从配置文件中获取。 ```js data() { return { APPID: "wx2188729b190d357d", APPSECRET: "d976b0e6262b829ba003e9a24032447c", }; }, ``` ```js // 根据code获取网站授权token getTokenFormCode(code) { http.get( `/weixin/sns/oauth2/access_tokenappid=${this.APPID}&secret=${this.APPSECRET}&code=${code}&grant_type=authorization_code` ).then((res) => { console.log(res.data.access_token,'根据code获取网站授权token'); console.log(res.data.openid,'获取到的用户openid'); }); }, ``` 然后在 `onLoad`中先判断路径上能否获取到 code 值,如果获取到后再调用接口去获取网页授权token ```js onLoad() { // 判断是否有code let weixinCode = this.getUrlCode("code"); // 当获取到code后再调用获取token的方法 weixinCode && this.getTokenFormCode(weixinCode); }, ``` ### 拉取用户信息 注意:这个方法需 `scope` 为 `snsapi_userinfo` 接口地址 ```http GET https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN ``` 编写方法 ```js // 根据网页授权token和openid获取用户基础信息 getAuthorizationInfo(token, openid) { http.get(`/weixin/sns/userinfo?access_token=${token}&openid=${openid}&lang=zh_CN`).then((res) => { console.log(res, "用户基础信息"); }); }, ``` 改写 `getTokenFormCode` 方法,接口调用成功后传递 `token` 和 `openid` 给 `getAuthorizationInfo` 方法来获取用户基本信息 ```js // 根据code获取网站授权token getTokenFormCode(code) { http.get( `/weixin/sns/oauth2/access_tokenappid=${this.APPID}&secret=${this.APPSECRET}&code=${code}&grant_type=authorization_code` ).then((res) => { const { access_token, openid } = res.data; this.getAuthorizationInfo(access_token, openid); }); }, ``` 接口返回结果 ![](https://gitee.com/szxio/h5_weixin/raw/master/src/static/README/8.png) ### 根据接口数据展示头像和昵称 在 `getAuthorizationInfo` 方法中添加如下代码,保存用户信息 ```js // 根据code获取网站授权token getAuthorizationInfo(token, openid) { http.get(`/weixin/sns/userinfo?access_token=${token}&openid=${openid}&lang=zh_CN`).then((res) => { // 解构赋值 const { headimgurl, nickname } = res.data; this.userInfo = { // 用户头像 headimgurl: headimgurl, // 用户微信昵称 nickname: nickname, }; }); }, ``` 在页面上展示用户信息 ```html {{ userInfo.nickname }} ``` 效果展示 ![](https://gitee.com/szxio/h5_weixin/raw/master/src/static/README/10.gif)