2023年11月28日发(作者:)

⼿把⼿实现微信⽹页授权和微信⽀付,附源代码

VUEandthinkPHP

wechat

⼿把⼿实现微信⽹页授权和微信⽀付,附源代码(VUE and thinkPHP)

概述

公众号开发是痛苦的,痛苦在好多问题开发者⽂档是没有提到的,是需要你猜的. 在开发过程中翻了好多的⽂档,都是说明其中的⼀部分问

题的,很费时间,所以在此总结⼤体过程。我们模拟的是⼀个⽀付的商城,在实现购买过程中基本是把微信公众号最主要模块实现了,其余的

功能我们没有涉及,但应该是触类旁通的。

我们叙述的过程是按开发流程进⾏叙述的,不会是按照开发⽂档的形式叙述,希望您能结合⼀起阅读,当然在流程中我们会提醒你阅读的部

vue2 + vuex + vue-router + webpack + ES6/7 + axios + sass + flex

后端技术栈

thinkPHP3.2 + mysql + 阿⾥云Linux Ubuntu

基本说明

开发环境 macOS 10.13.3 nodejs 8.0.0 centOS 7.4

本⽂中使⽤的url是 (demo), 开发过程中需要替换成你的URL。

如有问题请直接在 Issues 中提,或者您发现问题并有⾮常好的解决⽅案,欢迎 PR

本着线上线下⼀样的原则,最好申请两个认证微信公众号,⼀个是发布使⽤,⼀个是本地开发使⽤。微信⾃带提供的微信测试功能也

不太好⽤

2. 已经备案的域名

3. 域名解析到服务器 传送门

4. : 微信开发可定使⽤这个⼯具。必须把前端代码放到》服务器上》⽤这个⼯具调试。请仔细阅读

2. 设置web开发者⼯具

在开发-开发者⼯具-web开发者⼯具设置开发者账号

3. 设置IP ⽩名单

在设置-安全中⼼-IP⽩名单设置你服务器的IP,通过开发者ID及密码调⽤获取access_token接⼝时,需要设置访问来源IP为⽩名单。

4. 设置基本配置-开发者ID

设置开发者密码(AppSecret)

我们获取到的AppSecret (eg) a66b789009df271cde47aaaaaaa

5. 设置服务器基本配置

这部的⽬的是为了和微信服务器建⽴联系, 通过微信平台实现我们的业务逻辑。

详细版:

![image](///upload_images/2491178-87d4e2f74ea3da4b?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

接⼊微信公众平台开发,开发者需要按照如下步骤完成:

1、填写服务器配置

2、验证服务器地址的有效性

3、依据接⼝⽂档实现业务逻辑

下⾯详细介绍这3个步骤。

**第⼀步:填写服务器配置**

* 登录微信公众平台官⽹后,在公众平台官⽹的开发-基本设置页⾯,勾选协议成为开发者,点击修改配置按钮、。

* 填写服务器地址(URL)、TokenEncodingAESKey

* URL是开发者⽤来接收微信消息和事件的接⼝URL

* Token可由开发者可以任意填写,⽤作⽣成签名(该Token会和接⼝URL中包含的Token进⾏⽐对,从⽽验证安全性)

* EncodingAESKey由开发者⼿动填写或随机⽣成,将⽤作消息体加解密密钥。

* 同时,开发者可选择消息加解密⽅式:明⽂模式、兼容模式和安全模式。模式的选择与服务器配置在提交后都会⽴即⽣效

* 加解密⽅式的默认状态为明⽂模式,选择兼容模式和安全模式需要提前配置好相关加解密代码

第⼆步:验证消息的确来⾃微信服务器

现在如果你点击确认 按钮,肯定会报认证错误。因为我们没有做微信认证请求 接收。 开发者提交信息后,微信服务器将发送GET请求到填

写的服务器地址URL上,GET请求携带参数如下表所⽰:

参数描述

signature微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。

timestamp时间戳

nonce随机数

echostr随机字符串

开发者通过检验signature对请求进⾏校验(下⾯有校验⽅式)。若确认此次GET请求来⾃微信服务器,请原样返回echostr参数内容,则

接⼊⽣效,成为开发者成功,否则接⼊失败。加密/校验流程如下:

1. 将token、timestamp、nonce三个参数进⾏字典序排序

2. 将三个参数字符串拼接成⼀个字符串进⾏sha1加密

3. 开发者获得加密后的字符串可与signature对⽐,标识该请求来源于微信

微信官⽅提供在⽂档中提供了PHP原⽣⽰例

Thinkphp 3.2 验证⽰例

namespace HomeController;//命名空间注意⽤⾃⼰的

use ThinkController; //引⼊Think Controller

/**

* Class IndexController

* @package HomeController

* @name 微信服务器验证类

* @author weikai

*/

class IndexController extends Controller {

//微信服务器接⼊

public function index()

{

//这个echostr 只有说验证的时候才会echo 如果是验证过之后这个echostr是不存在的字段了

//定义你在微信公众号开发者模式⾥⾯定义的token 这⾥举例为weixin

$token = "weixin";

//三个变量 按照字典排序 形成⼀个数组

$tmpArr = array(

$token,

$timestamp,

$nonce

);

// 字典排序

sort($tmpArr, SORT_STRING);

$tmpStr = implode($tmpArr);

//哈希加密 laravel⾥⾯是Hash::

$tmpStr = sha1($tmpStr);

//哈希加密后的数据 和微信服务器传过来的签名⽐较

if ($tmpStr == $signature) {

return true;

} else {

return false;

}

}

/**

* @name 消息接收

* @author weikai

*/

public function responseMsg()//执⾏接收器⽅法

{

//获取微信服务器的XML数据 转化为对象 判断消息类型

但是我们第⼆次点击的时候是不需要点击授权的,这两个过程是不同的,是两种授权:(样例不可直接使⽤,是demo)

⾮静默授权的 URL 样例:(scope=snsapi_userinfo)

请注意加粗部分

点击`允许`即可带着⽤户信息跳转到第三⽅页⾯,如上图.

作⽤: 是⽤来获取⽤户的基本信息的

静默授权的 URL 样例: (scope=snsapi_base)

请注意加粗部分

在微信 web 开发者⼯具中打开类似的授权页 URL 则会`⾃动跳转`到第三⽅页⾯。

作⽤:是⽤来获取进⼊页⾯的⽤户的openid

注意:俩者授权区别

⾮静默授权:可获取微信⽤户基础信息如 ⽤户微信昵称 、城市、语⾔、头像、关注公众号时间、openid等。

静默授权:⽤户体验好,⽤户不知觉间完成授权,但只可以获取到⽤户得openid。

⽹页授权

请通读

请注意 章节

关于⽹页授权access_token和普通access_token的区别

具体⽽⾔,⽹页授权流程分为四步:

注意: 步骤⼀是由前台完成的,前台获取code 之后需要传给后台,由后台完成 2 3 4

1. 引导⽤户进⼊授权页⾯同意授权后微信跳转回调地址并传递参数code 获取code

2. 通过code换取⽹页授权access_token(与基础⽀持中的access_token不同)

3. 如果需要,开发者可以刷新⽹页授权access_token,避免过期

4. 通过⽹页授权access_tokenopenid获取⽤户基本信息(⽀持UnionID机制)

1、引导⽤户进⼊授权页⾯同意授权,获取code

建议:如果路由由vue管理,建议code由前台获取并发送给后台。 在公众账号中配置授权回调域名

(${redirect_url}看下⾯)

微信授权是前端发起的,

时机: 是在你需要获取微信信息之前的页⾯发起请求,当然⼤部分情况是⽤户进⼊webapp 我们就开始授权,我们的dome中就是进⼊

⽴马授权

前台(Vue): 前台做引导到授权页⾯,使⽤ 就可以实现。授权过程中会有⼏次这页⾯跳转。我们把授权函数放

Each((to, from, next)=> {}) 函数中,好控制。

后台(PHP): 前台调到了后台,后台此时需要获取code了。后台要通过 特定的URL(见官⽹第⼀步:⽤户同意授权,获取code)获

取code.

api参数解释:

appid : 请查看本⽂ 参数说明

redirect_uri : 回调链接,完成⽤户授权后微信服务器⾃动回调得uri,⼀般为业务⾸页链接(注意请转义)。

response_type : 固定为code 。

scope : 授权⽅式 可选静默(snsapi_base) 或者⾮静默(snsapi_userinfo)

state : 此参数可为业务需求使⽤,根据业务需要传⼊。

/**

* @name 授权引导后微信会跳转到回调地址并携带code参数

* @author weikai

*/

public function getBaseInfos(){

$redirect_url = I('ct_url');//获取前台传递的回调地址

$app_id = C('WX_APPID');//获取⾃⼰公众号的 appid

$redirect_uri = urlencode($redirect_url);//处理url

header('location:'.$url);

}

$url = "/connect/oauth2/authorize?appid=".$app_id."&redirect_uri=".$redirect_uri."&response_type=code&scope=snsapi_userinfo&st

错误返回码说明如下:

返回码说明

10003redirect_uri域名与后台配置不⼀致

前台截取出code 就可以了,传给后台,到这⾥基本就可以了。但是我们通常是⽤户每次登陆都需要进⾏授权,我们判断url中的参数就可以

实现了。往往我们也要监听⽤户是否登录,判断⽤户是否需要账号密码登录也需要在 Each((to, from, next)=> {})

现,beforeEach()有些复杂了,请⼤家阅读具体代码。请结合⾃⼰具体的业务书写

/**

* 判断⽤户是否需要账号密码登录,login页⾯监听

* @Author Hybrid

* @DateTime 2018-02-28

*/

let checkIsLoginGotologin = function(to, next) {

// isRelation 判断⽤户微信账户是否关联官⽹账户

// routeArr 是⼀些路由是不需要受监听的

// !res ? 已经授权 :没有授权

isRelation().then(res => {

if (es()) {

!res ? next('index') : next();

} else {

// 没有授权且不是授权页 // 当在授权的情况下是不允许访问login页⾯

(res && !== '/login') ? next('/login'): ((!res && === '/login') ? next('index') : next())

}

})

}

/**

* 获取和推送code

* @Author Hybrid

* @DateTime 2018-02-28

* @param {} url 路径

*/

let getCodePullCode = async function(url) {

let mycode = ing(f('code=') + 5, f('state=') - 1);// 前台截取code

('wechatCodeStr', mycode); // 存储code

//传送给后台code

await axios

.get("/home/WxSignature/getCode", {

params: {

code: mycode

}

})

.then(res => {

//需要登录

var res = ;

if (res && === 1) {

('openId', );//本地存储Openid,也可以不存储。由后台调配

= `/?a=1#${('#')[1]}`; // 增加a=1 防⽌⽀付错误 防⽌前台死循环

} else {

// 后台重定向页⾯,授权登录

(!(f('code=') < 1)) ? getCodePullCode(url): checkIsLoginGotologin(to, next)

}

})

}

2、通过code换取⽹页授权access_token(与基础⽀持中的access_token不同)

appid : 请查看本⽂ 参数说明

secret : 请查看本⽂ 参数说明

code :获取到得code。

grant_type : 固定为authorization_code

获取code后,请求以下链接获取access_token以及⽤户得openid:

/sns/oauth2/access_token?appid=你的appid&secret=你的sercret&code=刚刚获取得code&grant_type=authorization_code

/**

* 前台传递code,后台存储

* @Author weikai

* @DateTime 2017-11-23

* @return [type] [description]

*/

public function getCode() {

$code = I('');//授权⽤code

$appid = C('WX_APPID');//你的公众号appid

$secret = C('WX_APPSECRET');//你的公众号secret

// 组合获取的url

$url="/sns/oauth2/access_token? appid=$appid&secret=$secret&code=$code&grant_type=authorization_code";

// curl获取access_token openid

$result=$this->curl_get_contents($url);//curl get请求函数请⾃⾏百度

$result=json_decode($result,true);//json转数组

$data['openid']=$result['openid'];

$data['access_token'] = $result['access_token'];

$data['refresh_token'] = $result['refresh_token'];

参数描述

access_token⽹页授权接⼝调⽤凭证,注意:此access_token与基础⽀持的access_token不同

expires_inaccess_token接⼝调⽤凭证超时时间,单位(秒)

refresh_token⽤户刷新access_token

openid⽤户唯⼀标识,请注意,在未关注公众号时,⽤户访问公众号的⽹页,也会产⽣⼀个⽤户和公众号唯⼀的OpenID

scope⽤户授权的作⽤域,使⽤逗号(,)分隔

错误时微信会返回JSON数据包如下(⽰例为Code⽆效错误):

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

其实完成第⼆步就完成了基本的⽹页授权但是还没有获取到⽤户的信息,授权也没有实际作⽤了。

3、刷新access_token(如果需要)

由于获取⽤户信息所⽤得access_token有效时常⽐较短,如果想获取access_token后间隔时间较长获取微信⽤户基本信息请请求刷新

access_token api

我这⾥没有采⽤授权后拉取⽤户信息的api,⽽是采⽤⽤户信息获取的api。

请求⽅法

获取第⼆步的refresh_token后,请求以下链接获取access_token

/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参数

/**

* 刷新access_token

* @Author weikai

* @refresh_token ⽤与刷新access_token的参数

* @DateTime 2017-11-23

* @return [type] [description]

*/

public function reAccessToken($refresh_token) {

$appid = C('WX_APPID');//你的公众号appid

// 组合获取的url

$url="/sns/oauth2/refresh_token?appid=$appid&grant_type=refresh_token&refresh_token=$refresh_token";

返回说明

正确时返回的JSON数据包如下:

{ "access_token":"ACCESS_TOKEN",

"expires_in":7200,

"refresh_token":"REFRESH_TOKEN",

"openid":"OPENID",

"scope":"SCOPE" }

和上步返回的数据相同,⽬的就是刷新了access_token 的有效时间,有效期内可以使⽤access_token 和openid获取微信⽤户信息

/**

* @return mixed

* @name 使⽤全局access_token获取⽤户详细信息

* @author weikai

*/

public function getWxUserInfo($openid){

$access_token = $this->getAccess_Token();

$url = "/cgi-bin/user/info?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";

$data = $this->cUrl($url);

$data = json_decode($data);

if($data){