企业微信开发之授权登录

简介:

以前写过一篇公众号的授权登录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接入流程
image
使用OAuth2前须知
关于网页授权的可信域名
REDIRECT_URL中的域名,需要先配置至应用的“可信域名”,否则跳转时会提示“redirect_uri参数错误”。
要求配置的可信域名,必须与访问链接的域名完全一致。举个例子:

假定重定向访问的链接是:http://mail.qq.com:8080/cgi-bin/helloworld
配置域名 是否正确 原因
mail.qq.com:8080 配置域名与访问域名完全一致
email.qq.com 配置域名必须与访问域名完全一致
support.mail.qq.com 配置域名必须与访问域名完全一致
*.qq.com 不支持泛域名设置
mail.qq.com 配置域名必须与访问域名完全一致,包括端口号
假定配置的可信域名是 mail.qq.com:
访问链接 是否正确 原因
https://mail.qq.com/cgi-bin/helloworld 配置域名与访问域名完全一致
http://mail.qq.com/cgi-bin/redirect 配置域名与访问域名完全一致,与协议头/链接路径无关
https://exmail.qq.com/cgi-bin/helloworld 配置域名必须与访问域名完全一致
关于UserID机制
UserId用于在一个企业内唯一标识一个用户,通过网页授权接口可以获取到当前用户的UserId信息,如果需要获取用户的更多信息可以调用 通讯录管理 - 成员接口 来获取。

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

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

 
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

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

相关实践学习
基于函数计算快速搭建Hexo博客系统
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
相关文章
|
11天前
|
小程序 前端开发 API
微信小程序全栈开发中的异常处理与日志记录
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的异常处理和日志记录,强调其对确保应用稳定性和用户体验的重要性。异常处理涵盖前端(网络、页面跳转、用户输入、逻辑异常)和后端(数据库、API、业务逻辑)方面;日志记录则关注关键操作和异常情况的追踪。实践中,前端可利用try-catch处理异常,后端借助日志框架记录异常,同时采用集中式日志管理工具提升分析效率。开发者应注意安全性、性能和团队协作,以优化异常处理与日志记录流程。
|
11天前
|
小程序 安全 数据安全/隐私保护
微信小程序全栈开发中的身份认证与授权机制
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的身份认证与授权机制。身份认证包括手机号验证、微信登录和第三方登录,而授权机制涉及角色权限控制、ACL和OAuth 2.0。实践中,开发者可利用微信登录获取用户信息,集成第三方登录,以及实施角色和ACL进行权限控制。注意点包括安全性、用户体验和合规性,以保障小程序的安全运行和良好体验。通过这些方法,开发者能有效掌握小程序全栈开发技术。
|
11天前
|
JavaScript 前端开发 小程序
微信小程序全栈开发之性能优化策略
【4月更文挑战第12天】本文探讨了微信小程序全栈开发的性能优化策略,包括前端的资源和渲染优化,如图片压缩、虚拟DOM、代码分割;后端的数据库和API优化,如索引创建、缓存使用、RESTful API设计;以及服务器的负载均衡和CDN加速。通过这些方法,开发者可提升小程序性能,优化用户体验,增强商业价值。
|
11天前
|
小程序 前端开发 JavaScript
微信小程序全栈开发中的PWA技术应用
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中PWA技术的应用,PWA结合Web的开放性和原生应用的性能,提供离线访问、后台运行、桌面图标和原生体验。开发者可利用Service Worker实现离线访问,Worker处理后台运行,Web App Manifest添加桌面图标,CSS和JavaScript提升原生体验。实践中需注意兼容性、性能优化和用户体验。PWA技术能提升小程序的性能和用户体验,助力开发者打造优质小程序。
|
11天前
|
SQL 安全 小程序
探索微信小程序全栈开发的安全性问题
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的安全性问题,包括数据安全、接口安全、隐私保护和代码安全。为解决这些问题,建议采取数据加密、使用HTTPS协议、身份认证与授权、输入验证、安全审计及漏洞扫描以及安全培训等措施。通过这些方法,开发者可提升小程序安全性,保护用户隐私和数据。
|
29天前
|
JSON 小程序 C#
微信网页授权之使用完整服务解决方案
微信网页授权之使用完整服务解决方案
|
1月前
|
小程序 JavaScript
在使用微信小程序开发中用vant2框架中的Uploader 文件上传wx.uploadFile无反应和使用多图上传
网上有的说是bind:after-read="afterRead"的命名问题不支持-,但是我这儿执行了console.log("file",file);证明函数运行了。后来发现是multiple="true"原因开启了多图上传,如果是多图上传的话file就是数组了
25 2
|
1月前
|
移动开发 小程序 API
微信小程序的一些开发限制
微信小程序的一些开发限制
73 1
|
1月前
|
JSON 小程序 前端开发
微信小程序开发入门学习01-TDesign模板解读
微信小程序开发入门学习01-TDesign模板解读
|
1月前
|
小程序 前端开发 程序员
微信小程序开发入门教程-小程序账号注册及开通
微信小程序开发入门教程-小程序账号注册及开通

热门文章

最新文章