php 企业微信开发

2015-12-15 17:20:04 u013142781 阅读数 14160

时间葱葱,小宝鸽入职也有半年了,刚入的时候刚好有负责开发一个微信企业号的新项目。从项目的一无所有到第一版上线,再一步步完善升级。期间学到了许多东西。对微信开发也是有了一定的认识。在此,小宝鸽再次无私地分享给大家啦。

其实微信开发跟web开发没有多大的区别,只是经过了微信,然后再由浏览器打开。因为经过微信,因此你的web会附加一些微信平台所提供的一些功能,如获取用户地理位置、获取微信用户头像、拍照上传、发送微信消息等等,通过微信接口即可调用。要将web项目挂靠在微信公众平台上是需要一个帐号的。微信公众平号分为服务号、订阅号、企业号。这三种帐号有一些小区别,但是开发流程都是差不多的,只是开放的功能上有些区别,知道其中一种开发,其他的也差不多。关于具体区别先不作过多介绍,后面的文章会讲到。接下来我们以企业号为例带大家进入微信开发之旅。

接下来将从下面几个角度带大家了解微信开发:

(1)申请企业号体验号
(2)企业号的一些配置
(3)微信JS接口调用

好了现在马上开始:

一、申请企业号体验号

1.1、首先来到微信企业号的网址 https://qy.weixin.qq.com/

这里写图片描述

1.2、可以看到“开发者中心”字眼,点击进入相应页面

这里写图片描述

1.3、进入后可以看到“欢迎你,开发者”的公告,右侧有个“申请体验号”,点击进入相应页面。

这里写图片描述

1.4、进入“申请体验号”后,可以看到注册流程,按照注册流程填写相应资料并申请,验证邮箱绑定微信号后体验号就申请成功啦。

这里写图片描述

1.5、申请成功之后,回到https://qy.weixin.qq.com/,用微信扫一扫扫描登录下方的二维码,输入对应密码即可登录成功,来到你的微信企业号首页啦。

这里写图片描述

二、企业号的一些配置

2.1、添加子部门,如下图,将鼠标放到“企业号体验43560625”就会出现小下标,然后点击添加子部门,填写好信息保存,然后刷新页面即可。

这里写图片描述
这里写图片描述

2.2、添加成员,点击通讯录,然后如下图进行操作,即可添加成员。部门选择刚刚添加的部门

这里写图片描述

2.3、然成员关注该企业号,如果添加成员的时候有输入邮箱,可以在通讯录的成员管理那里给成员发送关注邀请,邀请会将企业号二维码发送到对应成员邮箱。另外一种方法直接点击“设置”即可看到体验号二维码。让成员扫这个二维码关注也是可以的(需要注意的是,体验号只能最多关注10个成员哦)。另外下图中的CorpID (wx7099477f2de8aded)非常重要的,先记录起来,下面接口微信JS调用的时候会用到。

这里写图片描述

2.4、添加管理组,点击“设置”–>”权限管理”,就会跳转到下图页面,然后“新建管理组”,选择管理员的时候,如果提示该成员已在其他管理组,那么估计需要添加成员了。小宝鸽添加了一个管理组“测试”,添加成功后如下图。其中Secret也是非常重要的东西,之后JS接口调用获取签名需要用到。

这里写图片描述

2.5、应用管理。猿友们可以看到左侧菜单中有个”应用中心”。点击应用中心将来到下图页面。”企业小助手”就是本企业号默认存在的一个应用。猿友们可以自行创建更多的应用。

这里写图片描述

点击”企业小助手”将会来到下面的界面,默认是回调模式,我们需要设置成普通模式。

这里写图片描述

点击”普通模式”,启用模式,然后启用”自定义菜单”。

这里写图片描述

自定义菜单启用完成之后,点击自定义菜单中的设置,将会跳转到如下页面:

这里写图片描述

添加菜单”测试”,然后设置”微信信息”,内容为”测试啦啦啦”,保存–>发布,然后右边有个预览,点击菜单”测试”,就会自动回复消息,如下图:

这里写图片描述

菜单响应除了发送微信消息也可以是跳转到某个链接,因为跳转链接是需要配置可信域名的,因此先介绍如何配置可信域名
应用管理还有一个地方需要设置的,那就可信域名,如下图,回到”企业小助手”应用的详情页面,添加可信域名,可信域名是有一些要求的(1. 设置的应用域名须通过ICP备案的验证,2. 请使用二级或二级以上域名),这里小宝鸽网上找了一个”yo.bbdfun.com”,猿友们也可以使用这个

这里写图片描述

配置了可信域名之后呢,猿友们可以配置跳转到链接的菜单啦,注意配置的url必须是已可信域名作为域名哈,例如:

这里写图片描述

三、微信JS接口调用

3.1、微信提供了一系列的JS接口,使得公众号企开发十分快捷高效,微信JS-SDK接口:
http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BE%AE%E4%BF%A1JS-SDK%E6%8E%A5%E5%8F%A3
各位猿友们可粗略看一下上面文档,便可知道大概提供的一些功能。

3.2、各位猿友们粗略看完”微信JS-SDK接口”,应该有看到下图的说明吧,接口的使用是需要注入权限验证配置的,现在我们上面的体验号等等的一系列操作就派上用场啦。

这里写图片描述

3.3、接下来将会一点点向大家介绍怎么调用微信接口啦

微信接口文档之后的猿友们应该都知道微信接口的调用步骤如下:

这里写图片描述

最重要的还是步骤二:权限验证配置。里面有几个参数,小宝鸽将会为猿友们一一介绍:
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来
appId: ”, // 必填,企业号的唯一标识,此处填写企业号corpid
timestamp: , // 必填,生成签名的时间戳
nonceStr: ”, // 必填,生成签名的随机串
signature: ”,// 必填,签名,见附录1
jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2

debug、appId和jsApiList相信各位猿友们应该都知道大概是什么东西。那么现在给各位猿友们重点介绍:timestamp、nonceStr、signature。
其实timestamp、nonceStr是用来生成signature的。
js生成时间戳方法:timestamp = Date.parse(new Date()); //1414587457
另外,nonceStr也是一串随机串,我们也用时间戳就好了nonceStr=Date.parse(new Date()); //1414587457

剩下的就是最关键的signature生成方法,这里需要引入access_token概念
生成signature签名第一步获得access_token:
浏览器输入:https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=wx5f24fa0db1819ea2&corpsecret=uQtWzF0bQtl2KRHX0amekjpq8L0aO96LSpSNfctOBLRbuYPO4DUBhMn0_v2jHS-9
即可得到access_token:YoxXjnJS57r8gk5Nf-Ki_mSvn98fILxv56EE7NFWE3qQNOH3OaW4iDWwLc05g1mdbuNhipK8fgy-q-pA93DqFw(其有效期为7200秒,即两个小时)

这里写图片描述

生成signature签名第二步通过access_token获得ticket:
浏览器输入:https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=YoxXjnJS57r8gk5Nf-Ki_mSvn98fILxv56EE7NFWE3qQNOH3OaW4iDWwLc05g1mdbuNhipK8fgy-q-pA93DqFw
即可得到ticket:”sM4AOVdWfPE4DxkXGEs8VLMMSNOZxIv5IhnWCyv5sA4UgJuWuMQdfMCeyC5kSL_c7OIMGeETC2y9PXfLbFIFNw(其有效期也是7200秒,即两个小时)

这里写图片描述

生成signature签名第三步通过ticket以及下面参数拼成字符串:
noncestr=1414587457
jsapi_ticket(即上面的ticket)=sM4AOVdWfPE4DxkXGEs8VLMMSNOZxIv5IhnWCyv5sA5kumyWTQ2VcKEcphBAW62J_HUgmaiKEQ3qhwj5Vlqq7g
timestamp=1414587457
url=http://mp.weixin.qq.com

通过上面的参数拼成(注意参数顺序必须一样):jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VLMMSNOZxIv5IhnWCyv5sA5kumyW
TQ2VcKEcphBAW62J_HUgmaiKEQ3qhwj5Vlqq7g
&noncestr=1414587457&timestamp=1414587457&url=http://mp.weixin.qq.com

最后利用上面的字符串进行sha1加密,有在线的校验工具http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign。但是真正开发的时候肯定是需要写代码的,下面附上sha1加密的java算法:`

jdk也有提供这个java.security这个包,里面封装好了sha1加密算法。使用方法可参考博主的另外一篇博客AES加密解密 SHA1、SHA加密 MD5加密

注意真正获取access_token、ticket的时候是需要通过代码实现的,上面在浏览器输入对应地址获取只是为了理顺流程。下面是通过java代码获取。

3.4、java代码获取签名

关于使用java代码获取签名的详细过程请参考博主的另外一篇文章 微信开发之使用java获取签名signature(贴源码,附工程)

该文章有详细的代码,而且附工程下载。

获取到了签名之后就可以调用微信js接口了,例子后面的文章将会讲到。

2019-07-26 14:07:50 Colden007 阅读数 639

企业微信回调配置

前期准备:
1.必须使用外网能够访问得到的URL(不能是本地服务器且URL要有备案)
2.需要使用官方推荐的“加解密库及返回码”(php)下载地址如下:https://github.com/sbzhu/weworkapi_php/tree/master/callback
3.要借助微信企业号接口调试工具: http://qydev.weixin.qq.com/debug

基础准备如果没有问题后,我们需要进入企业微信后台的应用程序如下图所示:

我们从上图可以看到
在这里插入图片描述
注:在测试回调配置前我们首先不需要填写URL,回调测试结束后再将URL放进去,在进行保存。
我们将测试回调的文件放在网站目录中,并取名叫callback.php来进行测试。
callback文件代码如下:

<?php
//这里的Getmessage_Wechat.class.php其实就是官网推荐的WXBizMsgCrypt.php
require_once "Getmessage_Wechat.class.php";

define(EncodingAesKey,"应用程序回调配置的EncodingAesKey");
define(Token,"应用程序回调配置的Token");
define(CorpId,"企业微信id号");

$wechatObj = new WXBizMsgCrypt(Token,EncodingAesKey,CorpId);

if (!isset($_GET['echostr'])) {	
	echo "没有进入到回调配置!";	
}else{
	//接受验证数据
	$sVerifyMsgSig = $_GET["msg_signature"];
	$sVerifyTimeStamp = $_GET["timestamp"];
	$sVerifyNonce = $_GET["nonce"];
	$sVerifyEchoStr = $_GET["echostr"]; 
	$sEchoStr = "";
	
	$errCode = $wechatObj ->VerifyURL($sVerifyMsgSig, $sVerifyTimeStamp, $sVerifyNonce, $sVerifyEchoStr, $sEchoStr);
//回调验证判断
		if ($errCode == 0) { 
		  echo $sEchoStr;
		} else { 
		  print("ERR: " . $errCode . "\n\n"); 
		}

	}
?>

此时借助“微信企业号接口调试工具” http://qydev.weixin.qq.com/debug来进行调试。如下图所示:
在这里插入图片描述
URL:必须使用外网能够访问得到的URL(不能是本地服务器且URL要有备案)
Token:企业微信应用程序->设置api中的信息
EncodingAesKey:企业微信应用程序->设置api中的信息
ToUserName: 企业id
EchoStr:想要输出的数据。用来检验回调内容是否成功,是否正确。

全部填完后点击“检查问题”。
在这里插入图片描述
如若EchoStr与返回结果一致,没有报错信息。
此时就可以再次回到“接受消息服务器配置”页面如图下所示:点击“保存”此时就会显示“保存成功”的页面啦!

在这里插入图片描述

在这里插入图片描述
但是小编在实际操作的过程中还是遇到很多坎坷的。其中遇到最多的回调报错就是提示:“echostr校验失败,请您检查是否正确解密并输出明文echostr”。

在这里插入图片描述
这里其实最主要的是要看我们在调试工具中的EchoStr的内容和返回结果内容是否一致,如果不一致就会有类似报错。那么是什么原因会导致这种结果的错误呢?可能原因如下:

1.要注意将PHP另存为无BOM头的UTF-8格式

2 是 EchoStr参数获取不要加 urldecode转换 (要命的是官方提供的示例就加了url转换,所以出错)即改成

$sVerifyEchoStr = $_GET["echostr"];  // 并不是 $sVerifyEchoStr = urldecode($_GET["echostr"]);

3.注意 PHP网页中 前面调试 OK后,到最后一步时,要把前面所有的 echo 或 print 代码去掉,要保证最后输出的只有 $sEchoStr 否则也会有同样报错。

上述是小编对于企业微信的回调配置做出一些经验,内容可能不是很完整,还望网友们指出。

2018-11-17 23:41:27 duringnone 阅读数 1855

企业微信应用开发那些事

简介: 本篇博文是针对本人上传的企业微信PHP-SDK进行讲解的,因为当时开发企业微信时,一直没有找到相关的参考资料,官方提供的PHP-SDK也是存在各种问题,所以在这里介绍一下自己开发过程中遇到的问题和解决方法,如果问题或异议,欢迎讨论

一、SDK修改简介

1、企业微信的逻辑结构(设计思路)

	1) PHP-SDK采用的是DI(依赖注入)容器设计模式构建的,DI可以使得代码降低代码的耦合度,但是要求开发者对各个功能类都要有一定的了解,因为DI容器需要开放者指定对象注入到工具类中,才能调用相应的功能方法来实现对应的功能,这样说比较抽象,来个实例说明一下(以ThinkPHP5框架为例):
	
		// 用户类		
		class User extends \think\Model		// \think\Model是数据库基类,Tp5的框架源码类
		{
			public  $name = null;
			public  $sex = null;
			public  $email = null;
			//构造方法
			public function __construct($name = null, $sex = null, $email = null) {
				$this->name = $name;
				$this->sex = $sex;
				$this->email = $email;
			}
			// 新增用户数据
			public function addUser() {
				$data = [
					'username' => $this->name,
					'sex' => $this->sex,
					'email' => $this->email
				];
				return $this->insert($data);		//add()方法将数据插入数据库
				// $this->insert($data);		// 演示示例 2
			}
		}

		//工具类
		class Tool
		{
			public $obj = null;
			public function __construct($object) {
				$this->obj = $object;
			}
			//新增数据库记录
			public function add() {
				return $this->obj->addUser();	//添加数据
				// $this->obj->addUser();		// 演示示例 2
			}
		}
		$userObj = new User();
		$userObj->name = '王二麻子';
		$userObj->sex = '保密';
		$userObj->email = 'wangermazi@163.com';
		$toolObj = new Tool($user);	
		$toolObj->add();
	
		解释: 将User类实例化为对象$userObj,并为对象$userObj属性赋值,再将对象$userObj注入到Tool类中; 此处的Tool类,类似一个中转站,只负责传递对象,具体的功能仍由对象中的功能方法实现;以上就是一个最简单的依赖注入模型; 

	2) 此SDK中, DI(依赖注入)容器 虽然可以降低代码耦合度,但是因为每个人使用的习惯问题, 有些人可能会将值通过进行传递,而不会在方法中直接return 执行结果,如 演示示例2 所示, 这样的不足在于,当代码因发生中断时,属性值会丢失,所以可以将一些必要的值进行缓存,比如 接口的token值, 就可以缓存在redis/memcached, 而不是存放在类的属性中;

2、企业微信的目录结构

	1) 
		├─weworkapi           
		│  ├─api        功能接口目录
		│  │  ├─datastructure      功能类目录
		│  │  │  ├─approvaldata	OA数据接口
		│  │  │  ├─batch				批量数据处理目录
		│  │  │  ├─checkdata		打卡数据目录1(OA数据子集)
		│  │  │  ├─checkoption	打卡数据目录2(OA数据子集)
		│  │  │  ├─external			外部联系人目录
		│  │  │  ├─invoice			电子发票目录
		│  │  │  ├─menu				自建应用主页菜单目录
		│  │  │  ├─message		自建应用消息目录
		│  │  │  ├─oauth				oAuth权限认证目录
		│  │  │  ├─pay				企业微信支付目录
		│  │  │  ├─servicecrop		第三方服务商功能类
		│  │  │  ├─servicecrop		第三方服务商功能类
		│  │  │  ├─tag			标签目录
		│  │  │  ├─user		企业成员目录
		│  │  │  ├─Agent.php		自建应用类
		│  │  │  └─Department.php	企业部门类
		│  │  ├─examples      测试例子目录(仅供参考,修改后可能无效)
		│  │  ├─ src     工具类目录(类似第一点中结束的Tool类作用)
		│  │  │  ├─API.php			工具基类
		│  │  │  ├─CorpAPI.php		企业工具类
		│  │  │  ├─ServiceCorpAPI.php 	为服务商开放的接口,使用应用授权的token
		│  │  │  └─ServiceProviderAPI.php 为服务商开放的接口,使用应用授权的token
		│  │
		│  ├─callback                回调操作(第三方或服务商回调的操作)
		│  │
		│  ├─utils                异常类目录
		│  │ ├─Utils.php          公共功能类
		│  │ ├─HttpUtils.php       的curl请求http参数处理类 
		│  │ └─...			其他的都是异常处理类
		│  │
		│  ├─config.php           调试配置文件
		│  ├─README.md 	

3、注意

	1) 修改后的PHP-SDK中 部分文件中有  
		use \think\Cache;
		use \think\Config;
		use \think\Request;
		这些类均为ThinkPHP5.*中的源码基类, 只要使用的是ThinkPHP5.*的框架都不会出错,但是这些文件中的配置需要自行添加,
		A) 如本人使用的cache是redis 需要在 /application/config.php 的 cache配置中添加redis的配置信息;
		B) SDK 中有很多处加载过Config::get('wework') , 或Config::get('wework.CORP_ID');
		是在config.php中添加了企业微信配置信息(二维数组)
		'wework' => [
			'CORP_ID' => '你的企业ID',
			'CORP_SECRET' => '你的企业微信SECRET',			// 有读写权限的secret
			'CORP_EXTERNAL_SECRET' => '只读权限的SECRET',		//外部联系人接口使用的是只读权限的secret
		]; 

二、遇到的问题及解决方案

	1) 部分代码出错
		A) 问题: 修改前的PHP-SDK中的Untils中有些判断 $val == null , 导致 to_invite = false 时失效(to_invite是否邀请外部成员加入企业微信) 
		B) 解决方案: 使用 $valu === null 判断, 目前已修正
	
	2) 接口调用过程不清晰问题
		A) 问题: 无法监控企业微信接口调用的情况
		B)解决方法: 在企业微信接口调用时,将调用记录写入日志表,目前记录调用日志的代码已植入/weworkapi/api/src/API.php中_addApiLogs 方法, 只需根据_addApiLogs方法的键名作为字段,在数据建立一个日志表即可
	3) token和调用频次的处理
		A) 因为token都有时效性,一般token有效期为7200秒,且系统会限制token的调用频次(限制阈值,如: 获取token接口调用次数不得超过 20次/天)
		B) 这个问题是出于个人建议,因为时间关系,目前还没有在SDK实践,就是将SDK中的access_token,provider_token,等存入缓存中,(目前SDK是将这些token的值都存放在属性中),这时token值存入缓存明显更稳定了
		C) 不仅是token, 包括SDK中还涉及到获取JS-SDK的ticket和 jsApiTicket 等值,ticket值和jsApiTicket都和token类似,因此可以考虑使用缓存记录ticket值和jsApiTicket,并设定缓存有效期; 其实涉及到调用频次限制的问题,都可以考虑缓存进行解决
	4) 另外还需注意一个重要问题,企业微信的接口调用次数,数据处理量也有严格的限制,具体请参照企业微信官方文档,

三、总结


1) SDK修改前后对比: 
		A) 修改前: 原SDK是以面向过程的思维处理的,可直接通过include 文件进行调用,无法再框架中直接使用
		B) 修改后: 依据PSR规范对部分代码进行修改, SDK的结构遵循Tp5的目录格式(即PSR规范)

2) 调试工具
	1) 这一点官方文档也有,但是光从文字上很难理解,工具文件名为 devtools_resources.pak
	2) 安装方法: 将devtools_resources.pak 文件下载到本地,并将此文件放入企业微信安装包路径的根目录下,也就是对应的版本目录下,并重启企业微信客户端生效
	3) 使用方法: 
	4) 注意:
		A) 问题:  文件按 2) 中步骤操作完后,有时按照 3) 步骤 打开调试工具,会发现调试工具页面一片空白,
		B) 原因: 这说明devtools_resources.pak 文件丢失了, 常发生在企业微信客户端版本升级,因为升级时,旧版本号对应目录会被清空,同时devtools_resources.pak文件也被删除了
		C) 本地自行备份,企业微信客户端升级后,只需将devtools_resources.pak文件重新放入最新的版本号目录根目录下(建议下载完devtools_resources.pak文件后,自行备份devtools_resources.pak文件)
	5) 下载地址: 可以到本人的上载资源中下载(老弟学习也需要下载一些积分的资源,多包涵)

3) 最后,因为目前开发暂未涉及到SDK所有内容,可能有些地方的bug还没发现, 目前本人亲试过的几块内容有: 外部联系人模块 /weworkapi/api/datastructure/external, 应用消息发送模块 /weworkapi/api/datastructure/message (目前实现了图文类型,文本类型亲测有用), 应用菜单模块 /weworkapi/api/datastructure/menu 等
 
2019-05-13 14:58:47 dsn727455218 阅读数 9838

以前写过一篇公众号的授权登录https://blog.csdn.net/dsn727455218/article/details/65630151,今天给大家分享一下企业微信的授权登录。

大致都差不多流程

注意事项:

1.网页授权及JS-SDK需要在企业微信上配置可信域名

2.企业微信授权登录里面填写你的可信域名

调用流程为:
A) 用户访问第三方服务,第三方服务通过构造OAuth2链接(参数包括当前第三方服务的身份ID,以及重定向URI),将用户引导到认证服务器的授权页
B) 用户选择是否同意授权
C) 若用户同意授权,则认证服务器将用户重向到第一步指定的重定向URI,同时附上一个授权码。
D) 第三方服务收到授权码,带上授权码来源的重定向URI,向认证服务器申请凭证。
E) 认证服务器检查授权码和重定向URI的有效性,通过后颁发AccessToken(调用凭证)

企业微信OAuth2接入流程

使用OAuth2前须知

关于网页授权的可信域名

REDIRECT_URL中的域名,需要先配置至应用的“可信域名”,否则跳转时会提示“redirect_uri参数错误”。
要求配置的可信域名,必须与访问链接的域名完全一致。举个例子:

  • 假定重定向访问的链接是:http://mail.qq.com:8080/cgi-bin/helloworld:
配置域名 是否正确 原因
mail.qq.com:8080 correct 配置域名与访问域名完全一致
email.qq.com error 配置域名必须与访问域名完全一致
support.mail.qq.com error 配置域名必须与访问域名完全一致
*.qq.com error 不支持泛域名设置
mail.qq.com error 配置域名必须与访问域名完全一致,包括端口号
  • 假定配置的可信域名是 mail.qq.com:
访问链接 是否正确 原因
https://mail.qq.com/cgi-bin/helloworld correct 配置域名与访问域名完全一致
http://mail.qq.com/cgi-bin/redirect correct 配置域名与访问域名完全一致,与协议头/链接路径无关
https://exmail.qq.com/cgi-bin/helloworld error 配置域名必须与访问域名完全一致

关于UserID机制

UserId用于在一个企业内唯一标识一个用户,通过网页授权接口可以获取到当前用户的UserId信息,如果需要获取用户的更多信息可以调用 通讯录管理 - 成员接口 来获取。

缓存方案建议

通过OAuth2.0验证接口获取成员身份会有一定的时间开销。对于频繁获取成员身份的场景,建议采用如下方案:
1、企业应用中的URL链接直接填写企业自己的页面地址
2、成员操作跳转到步骤1的企业页面时,企业后台校验是否有标识成员身份的cookie信息,此cookie由企业生成
3、如果没有匹配的cookie,则重定向到OAuth验证链接,获取成员的身份信息后,由企业后台植入标识成员身份的cookie信息
4、根据cookie获取成员身份后,再进入相应的页面

构造网页授权链接

如果企业需要在打开的网页里面携带用户的身份信息,第一步需要构造如下的链接来获取code参数:


 
  1. https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect

参数说明:

参数 必须 说明
appid 企业的CorpID
redirect_uri 授权后重定向的回调链接地址,请使用urlencode对链接进行处理
response_type 返回类型,此时固定为:code
scope

应用授权作用域。

snsapi_base:静默授权,可获取成员的基础信息;
snsapi_userinfo:静默授权,可获取成员的详细信息,但不包含手机、邮箱;
snsapi_privateinfo:手动授权,可获取成员的详细信息,包含手机、邮箱。

state 重定向后会带上state参数,企业可以填写a-zA-Z0-9的参数值,长度不可超过128个字节
#wechat_redirect 终端使用此参数判断是否需要带上身份信息
agentid 企业应用的id。
当scope是snsapi_userinfo或snsapi_privateinfo时,该参数必填。
注意redirect_uri的域名必须与该应用的可信域名一致。


员工点击后,页面将跳转至 redirect_uri?code=CODE&state=STATE,企业可根据code参数获得员工的userid。code长度最大为512字节。

权限说明:
企业无限制;第三方使用snsapi_privateinfo的scope时,应用必须有’成员敏感信息授权’的权限。

根据code获取成员信息
请求方式:GET(HTTPS)
请求地址:https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE

参数说明:

参数    必须    说明
access_token    是    调用接口凭证
code    是    通过成员授权获取到的code,最大为512字节。每次成员授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

权限说明:
跳转的域名须完全匹配access_token对应应用的可信域名。

返回结果:
a) 当用户为企业成员时返回示例如下:

{
"errcode":0,
"errmsg":"ok",
"UserId":"USERID",
"DeviceId":"DEVICEID",
"user_ticket":"USER_TICKET",
"expires_in":7200
}

参数    说明
errcode    返回码
errmsg    对返回码的文本描述内容
UserId    成员UserID
DeviceId    手机设备号(由企业微信在安装时随机生成,删除重装会改变,升级不受影响)
user_ticket    成员票据,最大为512字节。
scope为snsapi_userinfo或snsapi_privateinfo,且用户在应用可见范围之内时返回此参数。
后续利用该参数可以获取用户信息或敏感信息。
 
expires_in    user_token的有效时间(秒),随user_ticket一起返回
非企业成员授权时返回示例如下:

{
"errcode":0,
"errmsg":"ok",
"OpenId":"OPENID",
"DeviceId":"DEVICEID"
}


参数    说明
errcode    返回码
errmsg    对返回码的文本描述内容
OpenId    非企业成员的标识,对当前企业唯一
DeviceId    手机设备号(由企业微信在安装时随机生成,删除重装会改变,升级不受影响)
出错返回示例:

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

实现代码:

package com.eqiao.bidata.weixin.controller;
 
import com.eqiao.bidata.weixin.common.AccessToken;
import com.eqiao.bidata.weixin.common.Result;
import com.eqiao.bidata.weixin.common.WeiXinQiYeConstants;
import com.eqiao.bidata.weixin.common.WeiXinQiYeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
 
/**
 * 单纯实现OAuth2验证,不使用注解及拦截器
 * Created by zhaoxinguo on 2017/7/11.
 */
@Controller
public class SimpleOAuth2Controller {
 
    private Logger logger = LoggerFactory.getLogger(SimpleOAuth2Controller.class);
 
    /**
     * 拼接网页授权链接
     * 此处步骤也可以用页面链接代替
     * @return
     */
    @RequestMapping(value = { "/oauth2wx.do" })
    public String Oauth2API(HttpServletRequest request){
        //获取项目域名
        String requestUrl = request.getServerName();
        String contextPath = request.getContextPath();
        logger.info("domain name: " + requestUrl + " project name: " + contextPath);
        //拼接微信回调地址
        String backUrl ="http://" + requestUrl + contextPath + "/oauth2me.do";
        String redirect_uri = "";
        try {
            redirect_uri = java.net.URLEncoder.encode(backUrl, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            logger.error("ecdoe error: " + e.getMessage());
        }
        String oauth2Url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + WeiXinQiYeConstants.CORPID + "&redirect_uri=" + redirect_uri
                + "&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
        return "redirect:" + oauth2Url;
    }
 
    /**
     * 授权回调请求处理
     * @return
     */
    @RequestMapping(value = { "/oauth2me.do" })
    public String oAuth2Url(HttpServletRequest request, @RequestParam String code){
        // 调用获取access_token的接口
        AccessToken accessToken = WeiXinQiYeUtil.access_token();
        HttpSession session = request.getSession();
        if (accessToken != null && accessToken.getAccess_token() != null) {
            // 调用获取用户信息的接口
            String UserId = getMemberGuidByCode(accessToken.getAccess_token(), code, WeiXinQiYeConstants.AGENTID);
            logger.info("UserId: " + UserId);
            if (UserId != null) {
                session.setAttribute("UserId", UserId);
                logger.info("UserId放入session成功!");
            }
        }
        // 这里简单处理,存储到session中
        return "user/result";
    }
 
    /**
     * 调用接口获取用户信息
     *
     * @param token
     * @param code
     * @return
     */
    public String getMemberGuidByCode(String token, String code, String agentId) {
        logger.info("code==" + code + " token=" + token + " agentId=" +agentId);
        Result result = WeiXinQiYeUtil.oAuth2GetUserByCode(token, code, agentId);
        logger.info("result= " + result);
        if (result.getErrcode().equals("0")) {
            if (result.getUserId() != null  && result.getUserId().length() > 0) {
                // 此处可以通过微信授权用code还钱的Userid查询自己本地服务器中的数据
                logger.info("result.getUserId(): " + result.getUserId());
                return result.getUserId();
            }
        }
        return "";
    }
 
}

/**
     * OAuth2验证接口根据code获取成员信息
     *
     * @param token
     * @param code
     * @return
     */
    public static Result oAuth2GetUserByCode(String token, String code, String agentId) {
        Result result = new Result();
        String menuUrl = WeiXinQiYeConstants.GET_OAUTH2_URL.replace("ACCESS_TOKEN", token).replace("CODE", code).replace("AGENTID", agentId + "");
        String userinfo = JHttpUtils.doGet(menuUrl);
        logger.info("userinfo: " + userinfo);
        JSONObject jsonObject = null;
        if (userinfo != null) {
            try {
                jsonObject = JSONObject.fromObject(userinfo);
                logger.info("jsonObject: " + jsonObject);
                if (jsonObject.getString("UserId") != null && jsonObject.getString("UserId").length() > 0) {
                    result.setErrmsg(jsonObject.getString("errmsg"));
                    result.setErrcode(jsonObject.getString("errcode"));
                    result.setUserId(jsonObject.getString("UserId"));
                } else {
                    result.setErrmsg(jsonObject.getString("errmsg"));
                    result.setErrcode(jsonObject.getString("errcode"));
                }
            } catch (Exception e) {
                result.setErrmsg("accessToken 超时......");
                result.setErrcode("42001");
            }
        }
        return result;
    }

一个完整的流程就是这样。

如遇到问题欢迎进群308742428

喜欢的朋友可以关注下,粉丝也缺。

2018-06-21 11:18:16 qq_38997379 阅读数 8776

    开发之前一定要搞明白,企业微信不是企业微信号,虽然有相似之处,但不尽相同!!!

    企业微信第三方应用与企业微信自建应用也不相同,一定要区分! !!

    本地测试完成,没问题了,直接提交上线,就OK啦!!!

1.官网地址:https://work.weixin.qq.com/,首先(注册/)登陆,然后点击右上角,服务商管理后台(前提是已成为服务商)

2.点击服务商信息,设置IP白名单,多个以英文逗号隔开,如果不设置,会提示没有权限或其他错误

3.点击标准应用服务,创建本地应用,每个企业可添加10个应用,应用类型分为两种,普通应用和通讯录应用,若普通应用需要跟企业微信后台通讯录同步,就必须要建一个通讯录应用!!!否则会提示没有权限。

4.填写信息,第一步就是根据个人需求填写基本信息,第二步是重点,特别是下图红色框中的“数据回调url”,和“指令回调url”,这两个url地址是一样的,而且这两个验证不通过,其他一切都为0.


5.下面就是重点代码开发的过程了,点击保存时,企业微信会以每10分钟推送一次suite_ticket到该地址,注意要缓存suite_ticket,其中这个是分为两个过程的,第一步先验证该url,第二步,推送suite_ticket。官网demo下载地址:https://work.weixin.qq.com/api/doc#10128/php%E5%BA%93

6.把demo中用到的文件放到自己的项目中来引用,我的yii框架开发的,tp的代码也差不多,比如你的指令回调url为127.0.0.1/ticket,那只需要参考下面代码放到你的控制器中即可,亲测可用!




7.这只是部分主要代码,如果有不懂的小伙伴可以加群QQ群:372319250(备注:企业微信开发),群文件下载“企业微信”,里面有完整的核心代码,有不懂的问题可以直接在群里问,@群主即可。

8.企业微信第三方应用开发的其他问题,一概在群里问,我能知道的一定倾囊相助,注意微信文档有很多坑,特别是像我这样的小白,一定注意哈!