开通微信支付支付产品
首先要在微信支付申请成为 微信支付商户。
选择开通具体的支付产品
成为微信支付商户后在管理后台选择微信支付中的具体支付产品并申请开通如 JSAPI 。
将支付商户与公众号关联
这一步是可选的,是由具体的支付产品是否需要与公众号交互决定,如本例中的JSAPI就需要公众号的支持。拥有支付功能的商户需要与某公众号关联,才能互相获取相应权限和数据,如JSAPI就需要通过关联的公众号获取用户 openid 用于识别用户。关联的方法是进入商户后台 APPID授权管理 页面,新增提交要关联某公众号申请,需要输入的 APPID 要从被关联的公众号处获得。申请提交后该公众号在 微信支付 商户号管理 待关联商户号 处进行确认授权。
点击查看官方指引
一通头疼的配置( !!-- )
管理后台配置
支付授权目录
进入商户后台 开发配置 支付配置,新增 公众号支付 的支付授权目录,该目录是商家的后台(开发)服务也就是向微信支付发起请求的服务器的程序运行目录,支持路径,但不支持自定义端口。应设置为接口所在目录并以/结尾,即如果接口完整路径为 http://domain/wxpay/jsapi.php 那该目录应该被设置为 http://domain/wxpay/ 而不应该是其它任何形式。
公众号接口权限
进入公众号后台,进入 设置 公众号设置 功能设置 网页授权域名,将网页授权域名按官方指导设置为开发服务器上允许获取微信用户 openid 的域名,也就是微信授权数据回调要访问的域名,只有先在微信这儿登了记的域名微信才会向其传输数据,相当于白名单。本例中,将目录设置为 wxpay.txxxt.com,并将该页面中微信提供的验证文件按要求放到目录下,即可正确设置。可以通过查看 开发 接口权限 网页授权获取用户基本信息 的显示结果判断是否设置完毕。
用于开发调试的微信号要关注该公众号
在公众号内绑定开发人员微信号
进入该公众号的管理后台,开发 开发者工具 web开发者工具 页面中,点击 绑定开发者微信号 将关注了该公众号的开发所用的微信号添加到列表中,在使用 web开发者工具 时用被绑定的微信号登录开发者工具,将可以获取到相关数据,如 openid,否则无法获取,因为公众号不认识当前调用它的人。
开发环境准备
Web(H5+后端接口)可以使用任何习惯的工具开发即可
下载 微信web开发者工具
在开发/调试中,涉及到微信Api调用(访问微信服务器)的,均需使用 微信web开发者工具 的公众号网页功能访问要调试的页面,不能使用普通浏览器。因为 开发者工具 具有普通浏览器没有的微信Api特性。
本例中项目路径 http://wxpay.txxxt.com/jsapi/,getCode.php 接口创建获取 code 的完整链接并发出请求,codeCallback.php 接口用于接收从微信发出的回调,成功将包含 code 的值,log.php 记录日志,jsapi_access_log.log 为日志文件。PHP 作为接口开发语言,使用 微信web开发者工具 公众号网页调试功能访问接口跟踪结果。
开发实践
第一步,用户同意授权,获取 code
code 是用来取得 openid 的钥匙,先访问微信指定的api取得 code,再拿 code 去换取 openid 是第一步要做的事情。
获取 code 只需按照微信给出的固定访问方式,拼接参数,请求指定接口,如无错误即可获得,详见下
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
这是微信的标准接口,我们需要处理里边几个参数
- appid,必填,在 微信公众平台 基本配置 公众号开发信息 开发者ID(APPID) 处获取
- redirect_uri,必填,urlencode处理,如参数无误微信接口将跳转回调此地址,并附带上结果参数,详见下方 返回值 说明
- response_type,必填,返回类型,固定填写字符串 code
- scope,必填,应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
- state,选填,开发者自定义参数,可以填写a-zA-Z0-9,最多128字节,重定向后会带上
- #wechat_redirect,必填,无论直接打开还是做页面302重定向,必须带此参数
按微信要求,除参数名和参数值要正确填写外,顺序也不可更改,否则请求将失败,拼接完整请求并通过header方式访问见下例
//header('content-type:application:json;charset=utf8');
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:GET');
header('Content-type: text/html; charset=utf-8');
$appId = ""; // 此处填写公众号 appid
$redirectUrl = "http://wxpay.txxxt.com/jsapi/openIdRedirect.php"; //此处填写回调地址
$state = strval(time()); // 模拟自定义 state 参数
$baseUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?";
//拼接字符串得到完整接口地址,要保证参数顺序与官方接口示例一致
$requestUrl = $baseUrl;
$requestUrl = $requestUrl."appid=".$appId;
$requestUrl = $requestUrl."&redirect_uri=".urlencode($redirectUrl);
$requestUrl = $requestUrl."&response_type=code&scope=snsapi_base"; // 不调用授权页的方式
$requestUrl = $requestUrl."&state=".$state;
$requestUrl = $requestUrl."#wechat_redirect";
header("Location: $requestUrl"); //返回并直接跳转到拼接完成的接口地址去
exit();
看一个拼接好的地址样例
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxcc70xxxxxxxxxxbbf&redirect_uri=http%3A%2F%2Fwxpay.txxxt.com%2Fjsapi%2FopenIdRedirect.php&response_type=code&scope=snsapi_base&state=1561360134#wechat_redirect
返回值说明 接口访问成功的话,微信会根据 redirect_uri 回调如下
http://wxpay.txxxt.com/jsapi/openIdRedirect.php?code=081vlfXQ11LXM11TiPTQ19n7XQ1vlfXq&state=xxxxxx
接收回调的接口要有能处理 code 的能力,详见下
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:GET');
header('Content-type: text/html; charset=utf-8');
$code = isset($_GET['code']) ? $_GET['code'] : "";
$state = isset($_GET['state']) ? $_GET['state'] : "";
if($code == ""){
echo("获取失败,人家没给有效的 code");
} else {
echo("获取成功,拿到了 code");
}
处理回调的核心逻辑其实很简单,就是判断 code 的有效性,有值就对了,否则就参照官方文档的错误码检查问题原因。回顾一下刚才的过程
- 使用web开发者工具访问 getCode.php 接口,拼接完整请求地址,获得 code
- 访问成功微信回调
- 回调接口记录了微信回调结果,查看日志,的确收到了 code 值
第二步,AppID + AppSecret + code 获取 openid
首先,通过公众号的 微信公众平台 开发 基本配置 开发者ID 开发者密码(AppSecret) IP白名单 ,获取 AppID 和 AppSecret 两个关键信息(APPID第一步已经获得),需要注意的是,虽然微信的官方Wiki教程中并没有提到设置IP白名单,但在设置 AppSecret 时是被提示需要一并设置的。
按开发文档要求拼接参数,请求以下链接获取access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
四个参数均为必填项,其中 grant_type 的值 authorization_code 为固定值,代码示例如下
******http
第一步将获取到的 code = 011L1Tzo16tbFj0L7zAo1riQzo1L1Tzm 拼接完整
https://api.weixin.qq.com/sns/oauth2/access_token?appid=wxccxxxxxxxxxbbf&secret=2axxxxxxxxxxxxxxxxxx22&code=011L1Tzo16tbFj0L7zAo1riQzo1L1Tzm&grant_type=authorization_code
******
在 code 有效期内请求该接口获得响应结果,成功返回JSON如下
{
"access_token": "22_sAk0YqHOr8f71n0WYGs8jXkdOqgpl_b4Yag3KMStE1oTPJRHjSxdDVEH6E0Ma_WdQ6gflPB5Tkr0Rmpv0VK5Bw",
"expires_in": 7200,
"refresh_token": "22_VU66fwGFZtq9XpX9s0r0k0d5p4zKQhJ-D_QnQiIo2BMfzMOzPaiVfPfCOWBGalWZtKsevxqcmgUud9zATlc5Xg",
"openid": "oHxxxxxxxxxxxxxxxxxxmg",
"scope": "snsapi_base"
}
错误将返回
{"errcode":40029,"errmsg":"invalid code"}
至此,snsapi_base 方式获取 openid 的过程已经结束,下一篇将讲述如何使用 openid 请求预支付交易标识。