摘要:上一篇总结了微信企业号开发的入门篇,access_token接口调用,这篇咱们来看下微信企业号开发中的网页授权接口调用,这个接口一般都是用来实现微信企业号应用免登录或者获取关注的微信用户的个人信息时会用到。
下面摘自微信企业号官方文档:
网页授权
概述
企业微信提供了OAuth的授权登录方式,可以让网页和企业微信共享用户ID,从而免去登录的环节。
此文档面向网页开发者介绍企业微信网页授权如何使用及相关注意事项。
关于网页授权的可信域名
1、在开始使用网页授权之前,开发者需要先登录到企业管理端后台,选择“企业应用”选项卡,进入需要使用网页授权的应用并编辑“可信域名”表单项,此选项将用于网页OAuth2.0授权的时候进行安全验证。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头
2、可信域名配置规范为全域名,且需要通过ICP备案(否则在微信侧jssdk功能失效)。比如需要网页授权的域名为: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鉴权
3、域名的验证逻辑说明:由于一个企业可以自定义多个应用,每个应用都可以配置一个安全域名,在做oauth跳转的时候,只需要携带coprid即可,企业微信的后台会遍历该企业下面配置的所有应用并检查其配置的可信域名,只要任意一个应用的可信域名匹配则校验成功。
关于UserID机制
UserId用于在一个企业内唯一标识一个用户,通过网页授权接口可以获取到当前用户的UserId信息,如果需要获取用户的更多信息可以调用通讯录管理的成员接口来获取。
接入流程说明
企业应用中的URL链接(包括自定义菜单或者消息中的链接),均可通过OAuth2.0验证接口来获取成员的UserId身份信息。注意:此URL的域名,必须完全匹配企业应用设置项中的“可信域名”(如果你的redirect_uri有端口号,那么“可信域名”也必须加上端口号),否则跳转时会提示redirect_uri参数错误。
通过此接口获取成员身份会有一定的时间开销。对于频繁获取成员身份的场景,建议采用如下方案:
1、企业应用中的URL链接直接填写企业自己的页面地址
2、成员操作跳转到步骤1的企业页面时,企业后台校验是否有标识成员身份的cookie信息,此cookie由企业生成
3、如果没有匹配的cookie,则重定向到OAuth验证链接,获取成员的身份信息后,由企业后台植入标识成员身份的cookie信息
4、根据cookie获取成员身份后,再进入相应的页面
关键步骤
获取code
如果企业需要在打开的网页里面携带用户的身份信息,第一步需要构造如下的链接来获取code参数:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&agentid=AGENTID&state=STATE#wechat_redirect
参数说明:
参数 | 必须 | 说明 |
---|---|---|
appid | 是 | 企业的CorpID |
redirect_uri | 是 | 授权后重定向的回调链接地址,请使用urlencode对链接进行处理 |
response_type | 是 | 返回类型,此时固定为:code |
scope | 是 | 应用授权作用域。 snsapi_base:静默授权,可获取成员的基础信息; snsapi_userinfo:静默授权,可获取成员的详细信息,但不包含手机、邮箱; snsapi_privateinfo:手动授权,可获取成员的详细信息,包含手机、邮箱。 |
agentid | 否 | 企业应用的id。 当scope是snsapi_userinfo或snsapi_privateinfo时,该参数必填。 注意redirect_uri的域名必须与该应用的可信域名一致。 |
state | 否 | 重定向后会带上state参数,企业可以填写a-zA-Z0-9的参数值,长度不可超过128个字节 |
#wechat_redirect | 是 | 终端使用此参数判断是否需要带上身份信息 |
权限说明:
企业无限制;第三方使用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"
-
}
下面来看具体的代码实现:
1.SimpleOAuth2Controller.java
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; }
以上就是网页授权接口的调用示例,最后调用成功后,会打印出微信企业号的UserId(前提是这个微信号必须先关注改企业号才行)。
3.访问方法测试网页授权接口:http://域名:端口号/项目名称/oauth2wx.do
4.源码下载地址:http://git.oschina.net/micai/weixin-qiye