Force.com微信企业号开发系列(一) - 启用二次验证
微信于9月份推出企业号后引起了业界不小的反响,许多企业都在思索企业号将如何影响企业的运营,从本文开始,我将详细阐述微信企业号开发的相关知识,而本文将着重介绍如何实现更高安全机制的二次验证。
申请企业体验号:
企业号顾名思义就是企业来申请的号,申请时就像申请服务号一样,需要提供各种组织证明文件,对广大开发者来说很难操作,好在腾讯公司也像服务号一样开通了体验号申请,留意企业体验号的有效期间非常短,只有90天(服务号测试账号有1年有效期),且如果企业体验号长期不使用还会收到腾讯公司的提前失效提醒邮件。企业体验号的申请链接如下,开发者只需要按照腾讯公司的引导完成注册步骤,立刻就能获得体验号:
http://qydev.weixin.qq.com/try?t=experience
通讯录添加成员:
与公众号不同的是,因为是面向企业内部,所以腾讯允许企业主动添加粉丝,具体操作是进入到通讯录后点击+按钮添加新成员,留意作为唯一识别个人信息,微信号、手机号或者邮箱必须至少有一个,直接搜集微信号通常比较困难,一般可以使用企业HR数据库里的手机号和邮箱等信息,具体操作上除了手工添加还可以通过Excel模板导入以及通过腾讯企业号微信API来添加,关于API添加用户稍后章节介绍。
输入完成以后,可以将企业微信号的二维码发送给员工,员工扫描后会自动出现系统默认的企业号小助手,小助手会自动引导员工通过邮箱或手机验证码来完成员工身份绑定的过程,此为一次验证,企业自行确保通讯录员工数据的正确性,后续依赖于腾讯公司来进行员工验证,验证通过后通讯录状态列的问号会消失,表明一次验证通过:
启用二次验证:
一次验证通常能够满足大多数企业的要求,但对于员工信息以及权限管理比较严格的公司来说,一次验证还不足够放心,希望能够员工通过输入公司内部的用户名和密码再进行一次验证,此为二次验证,二次验证的启用位于企业号首页设置处,到设置画面后滚动画面找到二次验证,点击右侧的选择钮启用二次验证:
此时会弹出如下窗口需要输入企业的二次验证页面地址:
为此我们可以参考企业号官方接口文档http://qydev.weixin.qq.com/wiki/index.php?title=%E5%85%B3%E6%B3%A8%E4%B8%8E%E5%8F%96%E6%B6%88%E5%85%B3%E6%B3%A8在Force.com平台开发相应页面。
开发二次验证用页面:
同样,页面分成两个部分,一部分是显示部分,用来输入用户名和密码,页面示意图如下,用户输入用户名user以及密码123点击绑定按钮既可以完成绑定:
页面名称是EmployeeAuth,页面代码如下,有些属于apex代码特有的标签,无需做深入理解,重要是在第13行按钮的action属性指定了bind方法,当点击按钮的时候将调用控制器类EmployeeAuthController的bind方法:
<apex:page standardstylesheets="false" showHeader="false" sidebar="false" controller="EmployeeAuthController">
<font size="">
<h1>Please input your user name and password</h1>
</font>
<font size="">
UserName: user<br />
Password: <br /><br />
<hr/>
<apex:form >
UserName: <apex:inputText size="" style="height:100px" value="{!strUsername}" id="strUsername"/><br /><br />
Password: <apex:inputText size="" style="height:100px" value="{!strPassword}" id="strPassword"/><br /><br />
<center>
<apex:commandButton value="Bind" style="width:600px; height:100px;font-size:50px" action="{!bind}" id="bind" />
</center>
</apex:form>
{!msg}
</font>
</apex:page>
在解读EmployeeAuthController控制器类的代码前我们首先看看微信二次认证的步骤。
二次验证的步骤与机理:
1. 首先,当微信一次验证(或邮箱或手机号码等认证)完成后,微信会发送如下图所示的消息给到用户:
2. 页面跳转:
当用户点击这个图文的时候实际上打开了一个位于open.weixin.qq.com网站下面的网页,这个页面会做一些处理后跳转到前面在二次验证里设置的URL也就是我们正在开发的这个页面,在跳转的时候还会再我们设置的URL后面加上参数code=CODE&state=STATE,例如在本例里二次验证配置的URL是http://johnson0001-developer-edition.ap1.force.com/EmployeeAuth,那么从腾讯openweixin.qq.com跳转后实际打开的URL是http://johnson0001-developer-edition.ap1.force.com/EmployeeAuth?code=CODE&state=STATE 。这里的state参数是干嘛的腾讯公司并没有说明目前看也并不重要。重要的是code参数,利用这个参数可以调用腾讯的oauth2接口换取员工的userid,留意userid是一个很重要的概念,在企业号里没有微信OpenId一说,只有userid用来唯一标识用户,这个userid实际上就是我们在维护通讯录时的账号字段值:
3. 通过code调用腾讯oauth2接口换取员工userid
关于这个接口的说明参见腾讯文档http://qydev.weixin.qq.com/wiki/index.php?title=%E6%A0%B9%E6%8D%AEcode%E8%8E%B7%E5%8F%96%E6%88%90%E5%91%98%E4%BF%A1%E6%81%AF,也可以参加下方说明,这里需要特别说明的是access token和agentid:
做过微信公共号开发或者看过前面介绍相关开发文章的读者应该不会陌生,当主动调用腾讯的api时都需要access token已确保访问的正当性,获得access token相应的也有一个专门的接口,具体的介绍可以参见腾讯公司文档http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%BB%E5%8A%A8%E8%B0%83%E7%94%A8,简单点说获得access token实际就是通过以下接口:
https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=id&corpsecret=secrect
这个接口里Corpid好找,打开设置就能找到,如下图:
不过corpsecret就没那么好找,实际是需要系统管理员在后台创建管理组,创建管理组后就可以拥有相应的Secret,而这个Secret所拥有的访问权限就是系统管理员创建的管理组所拥有的权限,腾讯文章http://qydev.weixin.qq.com/wiki/index.php?title=Secret也有提到:
再回过头来说agentid腾讯文档里提到指的是“跳转链接时所在的企业应用ID”,在本例里其实指的就是发送“身份验证”图文消息的那个应用也就是“企业小助手”的应用ID,当然在不同的用户场景里可能会是不同的应用在调用换取userid接口,如何查看“企业小助手”的应用ID呢?进到应用中心,第一个就是企业小助手,点击进入就可以看到如下图所示的企业应用ID了:
4. 二次验证
拿到userid后实际就可以进行二次验证了,二次验证的方式有很多种,例如如果公司已经建立起良好的通讯录管理机制(userid等和企业人力资源数据库同步,入职离职员工均能和企业号通讯录同步),拿到userid后只要判断这个userid是一位在职员工就可以自动判断为二次验证通过,或者再保险点如本例演示的,要求员工输入公司的员工用户名和密码进行验证。留意,输入用户名和密码验证的页面也就是我们前面提到的二次验证页面是属于企业拥有也是企业开发的,这样就确保了企业对安全的控制,具体操作上,用户输入用户名和密码后企业可以调用已有的接口进行验证,如果验证成功则将员工的userid等信息保存在业务系统数据库中一遍后续操作。
5.通知腾讯关注成功
现在最后一步等企业在自己的网页里完成了用户验证后只剩下通知腾讯该用户已经验证成功让相应员工关注成功,此时应该调用如下接口,可以看到接口需要的第二个参数即是我们前面换回来的userid:
https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?access_token=ACCESS_TOKEN&userid=USERID
此接口的详细说明如下:
二次验证的代码实现:
按照前面的思路,我们首先获取从腾讯跳转过来的code,并通过code换取用户的userid,换取的这个过程在页面加载中完成,为此主要代码应放在类构造器里。下面的代码里设置了五个变量,其中strPassword和strUsername和用户在页面里输入的用户名和密码相对应,userID用来存储换回来的userid信息,msg用来调试帮助在页面里显示中间信息,accessToken则用来存储access token:
public class EmployeeAuthController { public String strPassword { get; set; }
public String strUsername { get; set; }
public String msg { get; set; }
public String userID { get; set; }
public String accessToken { get; set; } public EmployeeAuthController (){
accessToken = obtainAccessToken();
String code = ApexPages.currentPage().getParameters().get('code');
//Obtain user ID
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setMethod('GET');
req.setHeader('Accept-Encoding','gzip,deflate');
req.setHeader('Content-Type','text/xml;charset=UTF-8');
req.setHeader('User-Agent','Jakarta Commons-HttpClient/3.1');
req.setEndpoint('https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=' + accessToken + '&code=' + code + '&agentid=0');
String bodyRes = '';
try{
HttpResponse res = h.send(req);
bodyRes = res.getBody();
}
catch(System.CalloutException e) {
System.debug('Callout error: '+ e);
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, e.getMessage()));
}
msg = bodyRes ;
//String operation to obtain userID:
JSONParser parser = JSON.createParser(bodyRes);
while(parser.nextToken() != null){
if((parser.getCurrentToken() == JSONToken.FIELD_NAME)){
String fieldName = parser.getText();
parser.nextToken();
if(fieldName == 'UserId'){
userID = parser.getText();
}
}
}
msg = userID;
} }
上述代码第9行调用obtainAccessToken方法获取accessToken,后续会介绍该方法的详情,accessToken两个小时内会失效,所以这里采取实时获取的方式,当然可以设计的再巧妙些以省却每次实时获取accessToken的网络开销。第10行获得了从腾讯跳转过来时带的code参数,从第11行通过HttpRequest方法来调用换取接口获得userid,留意第18行指定了agentid为0,这是因为验证消息是从企业小助手应用发起的,而企业小助手应用id是0。第29行开始解析返回来的JSON数据获取userid。
下面是obtainAccessToken方法,方法内容也比较直接,主要通过调用gettoken接口来获取accessToken,并通过JSONParser类来解析返回的JSON数据以获得accessToken:
private String obtainAccessToken(){
String token;
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setMethod('GET');
req.setHeader('Accept-Encoding','gzip,deflate');
req.setHeader('Content-Type','text/xml;charset=UTF-8');
req.setHeader('User-Agent','Jakarta Commons-HttpClient/3.1');
req.setEndpoint('https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=wx548178d7f347f582&corpsecret=9pwWy0AVoT6V65hnwZLYdi4jnLLx65ofBRb_Ds0mAozysQoywDaqbqYCqglm2vhr');
String bodyRes = '';
try{
HttpResponse res = h.send(req);
bodyRes = res.getBody();
}
catch(System.CalloutException e) {
System.debug('Callout error: '+ e);
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, e.getMessage()));
}
msg = bodyRes;
JSONParser parser = JSON.createParser(bodyRes);
while(parser.nextToken() != null){
if((parser.getCurrentToken() == JSONToken.FIELD_NAME)){
String fieldName = parser.getText();
parser.nextToken();
if(fieldName == 'access_token'){
token= parser.getText();
}
}
}
msg = token;
return token;
}
接下来最重要的方法是bind方法,该方法将负责用户身份验证以及通知腾讯用户关注成功,可以看到下面代码里第2行到第6行只做了很简单的用户名密码校验,真实场景里可以根据企业的具体认证机制进行替换,从第9行开始也即企业内部用户认证通过后开始调用authsucc接口通知腾讯用户关注成功。
public PageReference bind() {
if(!strUsername.equals('user')){
msg = 'Please input correct user name';
}
else if(!strPassword.equals('')){
msg = 'Please input correct password';
}
else{
msg = 'Bind successfully!';
//Notify tencent to add user
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setMethod('GET');
req.setHeader('Accept-Encoding','gzip,deflate');
req.setHeader('Content-Type','text/xml;charset=UTF-8');
req.setHeader('User-Agent','Jakarta Commons-HttpClient/3.1');
req.setEndpoint('https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?access_token=' + accessToken + '&userid=' + userID);
String bodyRes = '';
try{
HttpResponse res = h.send(req);
bodyRes = res.getBody();
}
catch(System.CalloutException e) {
System.debug('Callout error: '+ e);
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, e.getMessage()));
}
msg = bodyRes ;
}
}
Force.com微信企业号开发系列(一) - 启用二次验证的更多相关文章
- 微信程序开发系列教程(二)使用JavaScript给微信用户发送消息
我之前的文章 微信程序开发系列教程(一)开发环境搭建 介绍了微信开发环境的搭建,这篇文章我们就来一步步开发一些具体的功能. 功能需求:当有微信用户关注了您的公众号之后,您用JavaScript发送一个 ...
- .net之微信企业号开发(三) 回调模式的接口开发
一.前言 微信企业号应用中,有两种模式,一种是普通模式,这种模式只能进行简单网页链接,以及发送固定的消息.为了可以让企业号的用户更好的与应用交互,微信提供了回调模式,这种回调模式的可以将用户发送给微信 ...
- .net之微信企业号开发(二) 企业号人员身份认证与开发
前言 这里完全可以链接一个登录页面,让用户输入用户名密码进行登录的...2333 但是,这样所就完全失去了微信企业号的意义,本来进入微信企业号的时候,就已经对人员身份进行认证了,你这里再让别人登录,不 ...
- .net之微信企业号开发(一) 所使用的环境与工具以及准备工作
前言 一直以来,从事的是.net winform的编程,虽然对移动互联这块很感兴趣,但是由于现有的工作和移动互联之间隔的太远,也就没有时间和精力好好的去研究和实现.今年年初辞职了,刚好朋友那里希望建立 ...
- 微信企业号开发之-如何获取secret 序列号
最近有项目基于微信企业号开发,简单记录下如何查看企业号secert 工具/原料 微信企业号 方法/步骤 用管理员的帐号登录后,选择[设置]-[权限管理]进入管理组设置界面 在左边点击[ ...
- 微信企业号开发入门(回调模式)java
最近在开发微信企业号,刚接触时云里雾里的,在摸索过程中终于清晰了一点. 刚开始我以为订阅号.服务号.企业号的接口差不多,就一直用订阅号的教程来入门,后来才发现差的挺多的. 首先,微信企业号不像订阅号和 ...
- 微信企业号开发(1)WebAPI在回调模式中的URL验证
微信回调模式的官方文档. 开发语言:C#(微信相关功能代码可以从官网下载) 首先,必须要明确几个参数,这几个参数在微信企业号中,每次调用都会使用到. 1.msg_signature:签名(已加密,加密 ...
- 微信程序开发系列教程(三)使用微信API给微信用户发文本消息
这个系列的第二篇教程,介绍的实际是被动方式给微信用户发文本消息,即微信用户关注您的公众号时,微信平台将这个关注事件通过一个HTTP post发送到您的微信消息服务器上.您对这个post请求做了应答(格 ...
- 微信企业号开发:corpsecret究竟在哪块呢?
开发微信企业号,获取ACCESS_TOKEN是必须的,但怎样获取ACCESS_TOKEN呢? 获取access_token=ACCESS_TOKEN" style="text-de ...
随机推荐
- Python Django开发 1
先配置个虚拟环境,在Flask第一篇文章有写,这里就跳过了 比如我的Django的目录是:C:\Workspaces\DjangoDemo,已经安装好了名为venv虚拟目录,接下来安装django框架 ...
- SNF开发平台WinForm之三-开发-单表选择控件创建-SNF快速开发平台3.3-Spring.Net.Framework
3.1运行效果: 3.2开发实现: 3.2.1 这个开发与第一个开发操作步骤是一致的,不同之处就是在生成完代码之后,留下如下圈红程序,其它删除. 第一个开发地址:开发-单表表格编辑管理页面 http: ...
- SmartJS 系列规划分享和背景介绍
发布了smartjs后,有朋友问:“没看懂究竟是干嘛的”.唉,打击了,每次我都想高唱其实你不懂我的心. 今天把相关的东西都整理了一遍,给大家介绍一下.里面绝大多数都已经实现过,有些则是有新的思路重做或 ...
- 获得 MongoDB for Node.js Developers 证书
前段时间由于项目需要,开始学习MongoDB,发现MongoDB官网的学习课程非常有帮助. 整个教学很有体系,包括: Video.quiz.Homework.Final Exam. 历时7周,拿到认证 ...
- ruby -- 进阶学习(二)paperclip上传图片
Need to add image attachments to a model? See how with paperclip in this episode. 在命令行输入: rails g pa ...
- 用JavaScript修改浏览器tab标题
修改tab或者window的标题,是一项较老的实践.Gmail 用它来提示用户新的聊天消息,当有新的page通过AJAX加载的时候,本站同样用它更新tab title.这是怎样做到的呢?当时是通过设置 ...
- MPU9250调试
MPU9250 芯片概述 MPU9250芯片是一个9轴姿态传感芯片,其中包含了3轴加速度传感器.3轴角速度传感器以及三轴磁力计. 其本质上是MPU6050芯片+AK8963. 可以获取传感芯片的加速度 ...
- .NET 产品版权保护方案 (.NET源码加密保护) (转载)
说 明:你希望自己用.net辛辛苦苦做出来的软件被人轻易破解吗?你希望自己花了大量人力物力用.net开发出来的产品被竞争对手轻易获取核心代码吗?这是 一篇比较详尽地介绍如何保护自己的.net源代码的文 ...
- 反射动态创建不同的Processor
1. 定义抽象方法 public abstract class BaseProcesser { public abstract void GetCustomerReportCard ...
- sprint3(第四天)
今天继续完成前台和后台的整合 燃尽图: