zoukankan      html  css  js  c++  java
  • 微信网页授权demo2

    1、在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头; 比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com无法进行OAuth2.0鉴权 (就是不能用)

    2、关于网页授权access_token和普通access_token的区别:我理解的就是 网页授权的access_token没什么特别的限制(虽然貌似也是2小时有效期)。大家随便无限制用;但是除此之外用到的access_token是有限制的。真的是有效期2小时,而且每天有获取access_token的限制次数。

    因为有限制次数,所以我在做的时候是把获取到的access_token保存在某个文件里,设置7000(小于一点点官方的2小时)秒过期,下次我再去获取access_token的时候看这个设置的过期时间有没有到。如果没到。就直接获取access_token值直接用。如果过期了,那么再次去获取下。再次保存到这个文件里去;

    另外普通过的access_token 是一个全局的共用的值,什么意思呢,比如你俩个模块都用到了access_token 但是你 俩个模块都单独存了一份access_token的文件。那么恭喜你,你中招了。因为 每次用户获取一次access_token的时候微信的服务器是缓存记录了最新access_token的最新值。比如你A模块获取更新了一次access_token,紧接着B模块也获取更新了一次access_token。那么,此时微信服务器缓存记录的是B模块获取的access_token值,再接着A模块去获取一次access_token。因为是紧接着嘛,那么俩小时肯定没到啊,也就是没过期啊,那么自动从access_token保存文件里获取值,可是实际此时微信服务器里缓存的access_token值 是B模块最新更新的值啊,那你继续进行你当前模块下涉及到access_token的运算,肯定是要提示access_token错误的(跟服务器的不一致啊);

    所以普通的access_token 一定要放在一个公共的,所有模块都调用的同一个地方。这样就避免了上面的错误;

    好了,下面进入正题。先介绍下微信网页授权的基本流程;

    1.你进入到某个页面,这个页面先判断地址url里有没有code参数;如果有code参数直接调用请求以下链接获取access_token:  https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code 可以获取到

    直接就可以获取到openid的值。 也就是完成了网页授权的基本流程,剩下你自己程序的操作了。

    2.如果这个页面没有code参数,那么先组装url到那个让用户点击授权的页面,

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect ;跳转到这个url去,得到下图

    用户点击确认登录之后。页面自动货跳转到  redirect_uri/?code=CODE&state=STATE。这个页面(redirect_uri是上面你自己设置url页面,默认就是用户刚开始进入第一个页面的url)。

    此时,等于又一次进入到当前页面了。默认会执行第一步判断操作(此时url获取的code的值),完成授权基本流程。

    getOpenId.php 代码如下

    <?php
    require_once "./lib/WxPay.JsApiPay.php";
    
    $tools = new JsApiPay();
    $openId = $tools->GetOpenid();
    echo $openId;
    ?>
    

    WxPay.Config.php代码如下

    <?php
    /**
    * 	配置账号信息
    */
    
    class WxPayConfig
    {
    	//=======【基本信息设置】=====================================
    	//
    	/**
    	 * TODO: 修改这里配置为您自己申请的商户信息
    	 * 微信公众号信息配置
    	 * 
    	 * APPID:绑定支付的APPID(必须配置,开户邮件中可查看)
    	 * 
    	 * MCHID:商户号(必须配置,开户邮件中可查看)
    	 * 
    	 * KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置)
    	 * 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert
    	 * 
    	 * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置),
    	 * 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
    	 * @var string
    	 */
    	const APPID = '123123213213';
    	const MCHID = '123123123123123123';
    	const KEY = '13123123123213';
    	const APPSECRET = '123123213213213123213123';
    	//=======【证书路径设置】=====================================
    	/**
    	 * TODO:设置商户证书路径
    	 * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载,
    	 * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书)
    	 * @var path
    	 */
    	const SSLCERT_PATH = '../xxxx/apiclient_cert.pem';
    	const SSLKEY_PATH = '../xxxx/apiclient_key.pem';
    	
    	//=======【curl代理设置】===================================
    	/**
    	 * TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0
    	 * 本例程通过curl使用HTTP POST方法,此处可修改代理服务器,
    	 * 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置)
    	 * @var unknown_type
    	 */
    	const CURL_PROXY_HOST = "0.0.0.0";//"10.152.18.220";
    	const CURL_PROXY_PORT = 0;//8080;
    	
    	//=======【上报信息配置】===================================
    	/**
    	 * TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】,
    	 * 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少
    	 * 开启错误上报。
    	 * 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报
    	 * @var int
    	 */
    	const REPORT_LEVENL = 1;
    }
    

    WxPay.JsApiPay.php代码如下

    <?php
    require_once "WxPay.Config.php";
    /**
     * 
     * JSAPI支付实现类
     * 该类实现了从微信公众平台获取code、通过code获取openid和access_token、
     * 生成jsapi支付js接口所需的参数、生成获取共享收货地址所需的参数
     * 
     * 该类是微信支付提供的样例程序,商户可根据自己的需求修改,或者使用lib中的api自行开发
     * 
     * @author widy
     *
     */
    class JsApiPay
    {
    	/**
    	 * 
    	 * 网页授权接口微信服务器返回的数据,返回样例如下
    	 * {
    	 *  "access_token":"ACCESS_TOKEN",
    	 *  "expires_in":7200,
    	 *  "refresh_token":"REFRESH_TOKEN",
    	 *  "openid":"OPENID",
    	 *  "scope":"SCOPE",
    	 *  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
    	 * }
    	 * 其中access_token可用于获取共享收货地址
    	 * openid是微信支付jsapi支付接口必须的参数
    	 * @var array
    	 */
    	public $data = null;
    	
    	/**
    	 * 
    	 * 通过跳转获取用户的openid,跳转流程如下:
    	 * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
    	 * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
    	 * 
    	 * @return 用户的openid
    	 */
    	public function GetOpenid()
    	{
    		//通过code获得openid
    		if (!isset($_GET['code'])){
    			//触发微信返回code码
    			$url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING'];
    			$baseUrl = rtrim($url, '/');
    			$baseUrl = urlencode($baseUrl);
    			$url = $this->__CreateOauthUrlForCode($baseUrl);
    			Header("Location: $url");
    			exit();
    		} else {
    			//获取code码,以获取openid
    		    $code = $_GET['code'];
    			$openid = $this->getOpenidFromMp($code);
    			return $openid;
    		}
    	}
    	
    	/**
    	 * 
    	 * 获取jsapi支付的参数
    	 * @param array $UnifiedOrderResult 统一支付接口返回的数据
    	 * @throws WxPayException
    	 * 
    	 * @return json数据,可直接填入js函数作为参数
    	 */
    	public function GetJsApiParameters($UnifiedOrderResult)
    	{
    		if(!array_key_exists("appid", $UnifiedOrderResult)
    		|| !array_key_exists("prepay_id", $UnifiedOrderResult)
    		|| $UnifiedOrderResult['prepay_id'] == "")
    		{
    			throw new WxPayException("参数错误");
    		}
    		$jsapi = new WxPayJsApiPay();
    		$jsapi->SetAppid($UnifiedOrderResult["appid"]);
    		$timeStamp = time();
    		$jsapi->SetTimeStamp("$timeStamp");
    		$jsapi->SetNonceStr(WxPayApi::getNonceStr());
    		$jsapi->SetPackage("prepay_id=" . $UnifiedOrderResult['prepay_id']);
    		$jsapi->SetSignType("MD5");
    		$jsapi->SetPaySign($jsapi->MakeSign());
    		$parameters = json_encode($jsapi->GetValues());
    		return $parameters;
    	}
    	
    	/**
    	 * 
    	 * 通过code从工作平台获取openid机器access_token
    	 * @param string $code 微信跳转回来带上的code
    	 * 
    	 * @return openid
    	 */
    	public function GetOpenidFromMp($code)
    	{
    		$url = $this->__CreateOauthUrlForOpenid($code);
    		//初始化curl
    		$ch = curl_init();
    		//设置超时
    		// curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout);
    		curl_setopt($ch, CURLOPT_URL, $url);
    		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
    		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
    		curl_setopt($ch, CURLOPT_HEADER, FALSE);
    		curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    		if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0" 
    			&& WxPayConfig::CURL_PROXY_PORT != 0){
    			curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
    			curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
    		}
    		//运行curl,结果以jason形式返回
    		$res = curl_exec($ch);
    		curl_close($ch);
    		//取出openid
    		$data = json_decode($res,true);
    		$this->data = $data;
    		$openid = $data['openid'];
    		return $openid;
    	}
    	
    	/**
    	 * 
    	 * 拼接签名字符串
    	 * @param array $urlObj
    	 * 
    	 * @return 返回已经拼接好的字符串
    	 */
    	private function ToUrlParams($urlObj)
    	{
    		$buff = "";
    		foreach ($urlObj as $k => $v)
    		{
    			if($k != "sign"){
    				$buff .= $k . "=" . $v . "&";
    			}
    		}
    		
    		$buff = trim($buff, "&");
    		return $buff;
    	}
    	
    	/**
    	 * 
    	 * 获取地址js参数
    	 * 
    	 * @return 获取共享收货地址js函数需要的参数,json格式可以直接做参数使用
    	 */
    	public function GetEditAddressParameters()
    	{	
    		$getData = $this->data;
    		$data = array();
    		$data["appid"] = WxPayConfig::APPID;
    		$data["url"] = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
    		$time = time();
    		$data["timestamp"] = "$time";
    		$data["noncestr"] = "1234568";
    		$data["accesstoken"] = $getData["access_token"];
    		ksort($data);
    		$params = $this->ToUrlParams($data);
    		$addrSign = sha1($params);
    		
    		$afterData = array(
    			"addrSign" => $addrSign,
    			"signType" => "sha1",
    			"scope" => "jsapi_address",
    			"appId" => WxPayConfig::APPID,
    			"timeStamp" => $data["timestamp"],
    			"nonceStr" => $data["noncestr"]
    		);
    		$parameters = json_encode($afterData);
    		return $parameters;
    	}
    	
    	/**
    	 * 
    	 * 构造获取code的url连接
    	 * @param string $redirectUrl 微信服务器回跳的url,需要url编码
    	 * 
    	 * @return 返回构造好的url
    	 */
    	private function __CreateOauthUrlForCode($redirectUrl)
    	{
    		$urlObj["appid"] = WxPayConfig::APPID;
    		$urlObj["redirect_uri"] = "$redirectUrl";
    		$urlObj["response_type"] = "code";
    		$urlObj["scope"] = "snsapi_base";
    		$urlObj["state"] = "STATE"."#wechat_redirect";
    		$bizString = $this->ToUrlParams($urlObj);
    		return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
    	}
    	
    	/**
    	 * 
    	 * 构造获取open和access_toke的url地址
    	 * @param string $code,微信跳转带回的code
    	 * 
    	 * @return 请求的url
    	 */
    	private function __CreateOauthUrlForOpenid($code)
    	{
    		$urlObj["appid"] = WxPayConfig::APPID;
    		$urlObj["secret"] = WxPayConfig::APPSECRET;
    		$urlObj["code"] = $code;
    		$urlObj["grant_type"] = "authorization_code";
    		$bizString = $this->ToUrlParams($urlObj);
    		return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
    	}
    }
    

      

    注意code只能用一次的。如果你第一次页面获取到openid了,你刷新这个页面。就会报错。

  • 相关阅读:
    题解 P2647 【最大收益】
    CF817E Choosing The Commander
    P2922 [USACO08DEC]Secret Message G
    洛谷月赛 P7107 天选之人
    如何在考场上快速用C++写高级对拍器
    题解 CF527D 【Clique Problem】
    P6768 [USACO05MAR]Ombrophobic Bovines 发抖的牛
    [USACO06NOV]Corn Fields G
    Orz 教主的比赛题解
    JZOI 4311 统一天下
  • 原文地址:https://www.cnblogs.com/phpjinggege/p/5886092.html
Copyright © 2011-2022 走看看