第一步:生成企业微信二维码
登录方式有两种,但是仅有第一步不同,后面方式不变
url直接给前端,由前端处理重定向,用户扫码后得到参数code,携参调用后端用户验证接口
网页授权登录:在企业微信中直接登录
扫码授权登录:在网站上,扫码登录
1、网页授权登录
-
API
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 state 否 重定向后会带上state参数,企业可以填写a-zA-Z0-9的参数值,长度不可超过128个字节 #wechat_redirect 是 终端使用此参数判断是否需要带上身份信息 -
返回值
-
直接返回带code的链接
http://api.3dept.com/cgi-bin/query?action=get&code=AAAAAAgG333qs9EdaPbCAP1VaOrjuNkiAZHTWgaWsZQ&state=# 拿到code调用后端接口
-
2、扫码授权登录
-
API
https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=CORPID&agentid=AGENTID&redirect_uri=REDIRECT_URI&state=STATE -
参数解析
参数 必须 说明 appid 是 企业微信的CorpID agentid 是 授权方的网页应用ID redirect_uri 是 重定向地址,需要进行UrlEncode state 否 用于保持请求和回调的状态,授权请求后原样带回给企业。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议企业带上该参数,可设置为简单的随机数加session进行校验 -
返回值
- 扫码

-
扫码后返回值
redirect_uri?code=CODE&state=STATE# 拿到code调用后端接口
第二步、获取AccessToken
AccessToken有效期是2小时(两小时内重复获取是不变的),频繁获取会报错,因此需要后端缓存起来(可以使用redis)
-
API
GET(HTTPS) https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET -
参数解析
-
corpid
-
corpsecret
-
-
返回值
{ "errcode": 0, "errmsg": "ok", "access_token": "accesstoken000001", "expires_in": 7200 } -
java实现
-
调用api
@FeignClient(name = "QYWechatApi", url = "https://qyapi.weixin.qq.com") public interface QYWechatApi { /** * 获取access_token * https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET */ @RequestLine("GET /cgi-bin/gettoken?corpid={corpId}&corpsecret={corpSecret}") WxTokenVO getAccessToken(@Param("corpId") String corpId, @Param("corpSecret") String corpSecret); } -
获取AccessToken
private WxToken getAccessToken(){ // 从redis获取accessToken,没有则获取新的并存入redis WxToken accessToken = (WxToken)redisTemplate.opsForValue().get("key"); if(accessToken == null){ accessToken = qYWechatApi.getAccessToken(QYWxConfig.CORP_ID, QYWxConfig.CORP_SECRET); if (accessToken.getErrcode() != null && accessToken.getErrcode() != 0) { log.error("获取企业微信账户accessToken异常: {}", JSON.toJSONString(accessToken)); } redisTemplate.opsForValue().set("key", accessToken.getAccess_token(), 119, TimeUnit.MINUTES); } return accessToken; }
-
第三步、获取访问用户身份
扫码后获得用户企业内唯一身份UserId(作用:与数据库中进行比对,如比对成功则登录成功,否则登录失败)
-
API
GET(HTTPS)https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE -
参数解析
-
access_token
第二步获取的
-
code
第一步获取的
-
-
返回值
{ "errcode": 0, "errmsg": "ok", "UserId":"USERID" } -
java实现
-
调用api
@FeignClient(name = "QYWechatApi", url = "https://qyapi.weixin.qq.com") public interface QYWechatApi { /** * 获取用户身份信息 * https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE */ @RequestLine("GET /cgi-bin/user/getuserinfo?access_token={accessToken}&code={code}") WxUserInfo getUserInfo(@Param("accessToken") String accessToken, @Param("code") String code); -
获取用户身份
public WxUserInfo getUserInfo(String code) throws EmcsCustomException { // 获得accessToken WxTokenVO accessToken = getAccessToken(); // 根据accessToken和code获得企业微信的userId WxUserInfo userInfo= qYWechatApi.getUserInfo(accessToken.getAccess_token(), code); if (userInfo.getErrcode() != null && userInfo.getErrcode() != 0) { log.error("根据token获取用户信息异常: {}", JSON.toJSONString(userInfo)); } return userInfo; }
-
第四步、获取成员详细信息(拓展步骤)
第三步获取的UserId是公司唯一,这步可以获得用户详细信息包括全局唯一open_userid
-
API
GET(HTTPS)https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=USERID -
参数解析
-
access_token
第二步获取的
-
userid
第四步获取的
-
-
返回值
{ "errcode": 0, "errmsg": "ok", "userid": "zhangsan", "name": "张三", "department": [1, 2], "order": [1, 2], "position": "后台工程师", "mobile": "13800000000", "gender": "1", "email": "zhangsan@gzdev.com", "is_leader_in_dept": [1, 0], "avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0", "thumb_avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/100", "telephone": "020-123456", "alias": "jackzhang", "address": "广州市海珠区新港中路", "open_userid": "xxxxxx", "main_department": 1, "extattr": { "attrs": [ { "type": 0, "name": "文本名称", "text": { "value": "文本" } }, { "type": 1, "name": "网页名称", "web": { "url": "http://www.test.com", "title": "标题" } } ] }, "status": 1, "qr_code": "https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx", "external_position": "产品经理", "external_profile": { "external_corp_name": "企业简称", "external_attr": [{ "type": 0, "name": "文本名称", "text": { "value": "文本" } }, { "type": 1, "name": "网页名称", "web": { "url": "http://www.test.com", "title": "标题" } }, { "type": 2, "name": "测试app", "miniprogram": { "appid": "wx8bd80126147dFAKE", "pagepath": "/index", "title": "my miniprogram" } } ] } } -
java实现
-
调用api
@FeignClient(name = "QYWechatApi", url = "https://qyapi.weixin.qq.com") public interface QYWechatApi { /** * 获取用户身份信息 * https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE */ @RequestLine("GET /cgi-bin/user/get?access_token={accessToken}&userid={userId}") WxUserInfo getUserDetailInfo(@Param("accessToken") String accessToken, @Param("userId") String userId); -
获取用户身份
public WxUserInfoVO getUserInfo(String code) throws EmcsCustomException { // 获得accessToken WxTokenVO accessToken = getAccessToken(); // 根据accessToken和code获得企业微信的userId WxUserInfo userInfo= qYWechatApi.getUserInfo(accessToken.getAccess_token(), code); if (userInfo.getErrcode() != null && userInfo.getErrcode() != 0) { log.error("根据token获取用户信息异常: {}", JSON.toJSONString(userInfo)); } // 根据企业微信的userId获得用户详细信息 userInfo = qYWechatApi.getUserDetailInfo(accessToken.getAccess_token(), code); if (userInfo.getErrcode() != null && userInfo.getErrcode() != 0) { log.error("根据userId获取用户详细信息异常: {}", JSON.toJSONString(userInfo)); } return userInfo; }
-
拓展API
-
获取部门信息
https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=ACCESS_TOKEN -
获取成员信息
https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=ACCESS_TOKEN&department_id=DEPARTMENT_ID&fetch_child=FETCH_CHILD




