企业微信小程序_授权登录接口获取用户userid

在这里插入图片描述

一、前置知识

获取小程序userid就要先将小程序提交审核->发布小程序->企微后台在自建应用中绑定小程序

1. 阅读 企业微信小程序开发文档

https://developer.work.weixin.qq.com/document/path/92426

2. 企业微信小程序登录流程

企业微信小程序获取access_token文档

在这里插入图片描述

3. 微信小程序区别

区分企业微信小程序登录流程和微信小程序登录流程不同点。

不同点:
1.企业微信小程序登录流程和微信小程序登录流程不一样,获取的用户信息也不一样。
2.企业微信小程序登录流程需要将企业微信小程序先发布上传吗,审核通过后,将企业微信小程序与企业应用进行绑定后,获取该应用的agentSecret和corpId去获取AccessToken,然后,通过AccessToken和code获取用户信息,最后通过获取的userid在调用通讯录接口获取该用户的详细信息。
3.开发阶段:可以使用企业微信提供的测试应用的agentSecret和corpId

二、前端部分
2.1. 调用登录接口

执行流程会从前端到后端:
前端调用腾讯企业微信登录接口api
登录api开发文档:https://developer.work.weixin.qq.com/document/path/91506
uniapp项目小程序项目写法:

           // 企业微信下程序登录的方法
			login() {
				wx.qy.login({
					success: function(res) {
					// 调用成功,会返回code
						console.log("res", res)
					}
				})
			},

返回的报文:

{code: "VFUfreDIauQszKQy5mZgRC3aaMijd7DM-xnOcZW3LVE", errMsg: "qy__login:ok"}

小程序项目写法:

//app.js
App({
  onLaunch: function() {
    wx.qy.login({
      success: function(res) {
        if (res.code) {
          //发起网络请求
          wx.request({
            url: 'https://test.com/onLogin',
            data: {
              code: res.code
            }
          })
        } else {
          console.log('登录失败!' + res.errMsg)
        }
      }
    });
  }
})
2.2. 请求后端接口

携带code调用后端接口
这里使用封装好的axios和user接口api,直接使用即可
utils/request.js,这个js主要封装了axios,对请求统一管理,请求url以及数据拼接以及响应处理(这个工具类需要和后端的返回对象JsonData.java对上,下面会贴出来代码)。

const BASE_URL = 'http://api.ant-qywx.com:9900';
function request({ url, data, method }) {
  return new Promise((resolve, reject) => {
    // 发起网络请求
    uni.request({
      url: BASE_URL + url,
      data,
      method,
      success: ({ data }) => {
		  console.log("data",data)
		  
        // 响应成功,获取数据,解析数据
        if (data.success) {
          resolve(data);
        } else {
          // 响应失败,给用户提示
          uni.showToast({
            title: data.message,
            icon: 'none',
            mask: true,
            duration: 3000,
          });
          reject(data.message);
        }
      },
      fail: (error) => {
        reject(error);
      },
      complete: () => {
        // 关闭加载
        uni.hideLoading();
      },
    });
  });
}

export default request;

引入api

<script>
    // 引用用户接口api 调用后端登录接口
	import {loginAuth} from '../../api/user.js';
</script>

编写登录方法调用企业微信登录接口

methods: {
// 企业微信下程序登录的方法
			login() {
				wx.qy.login({
					success: function(res) {
						console.log("res", res)
						loginAuth(res).then((response) => {
							console.log("response", response)
						});
					}
				})
			}
}

api/user.js这里js,作用是管理用户相关接口api

import request from '../utils/request';

/**
 * 微信用户授权登录,携带appid和code参数,调用后端接口获取Openid
 */
export function loginAuth(data) {
  return request({
    url: '/mini/login',
    data: {
      code: data.code,
    },
  });
}
2.3. 项目源码

https://gitee.com/gblfy/qywx-inner-java-api

三、后端部分
3.1. yml配置

application.yml

server:
  port: 9900
 
qywx:
  mini:
    agentSecret: i5t-rh8bXeNCgihcYPrG9ZPpWkivzPJ69sv570osk6I
    corpId: ww17f8d10783494584
3.2. 获取用户信息接口

Controller

package com.gblfy.qywxin.controller;

import com.gblfy.qywxin.service.QywxInnerMiniService;
import com.gblfy.qywxin.utils.JWTUtils;
import com.gblfy.qywxin.vo.JsonData;
import com.gblfy.qywxin.vo.QywxInnerUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("/mini")
public class QywxMiniController {
    private static final Logger logger = LoggerFactory.getLogger(QywxMiniController.class);

    @Value("${qywx.mini.corpId}")
    private String corpId;

    @Autowired
    private QywxInnerMiniService qywxInnerMiniService;

    @GetMapping("/login")
    public JsonData login(@RequestParam(value = "code", required = false) String code) {
        logger.info("accept code->{}", code);
        Map result = qywxInnerMiniService.getOauthUser(corpId, code);
        logger.info("accept result->{}", result);

        //本案例仅从企业微信接口获取未从数据表中获取
        QywxInnerUser user = new QywxInnerUser();
        user.setCorpId(corpId);
        user.setUserId((String) result.get("userId"));
        String token = JWTUtils.geneJsonWebToken(user);

        result.put("token", token);
        return JsonData.buildSuccess(result);
    }
}

3.3. 获取token

service

package com.gblfy.qywxin.service;

import com.gblfy.qywxin.config.QywxInnerConfig;
import com.gblfy.qywxin.utils.RestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class QywxInnerMiniService {

    private static final Logger logger = LoggerFactory.getLogger(QywxInnerMiniService.class);

    @Value("${qywx.mini.agentSecret}")
    private String AGENT_SECRET;

    public Map getOauthUser(String corpId, String code) {
        // 1.通过corpId获取AccessToken
        String accessToken = getAccessToken(corpId);

        String getOauthUrl = String.format(QywxInnerConfig.MINI_OAUTH_USER_URL, accessToken, code);
        Map response = RestUtils.get(getOauthUrl);
        if (response.containsKey("errcode") && (Integer) response.get("errcode") != 0) {
            logger.error(response.toString());
            return response;
        }
        System.out.println("response->" + response);

        //  目前已经获取到userid了
        // return response;
        //根据用户UserId->获取通讯录用户详情get
        String userId = (String) response.get("userid");
        String url = String.format(QywxInnerConfig.USER_DETAIL_URL, accessToken, userId);
        Map detaiResponse = RestUtils.get(url);

        //获取错误日志
        if (detaiResponse.containsKey("errcode") && (Integer) detaiResponse.get("errcode") != 0) {
            logger.error(detaiResponse.toString());
        }
        return detaiResponse;
    }

    /**
     * 通过corpId获取AccessToken
     *
     * @param corpId 企业ID
     * @return
     */
    public String getAccessToken(String corpId) {
        String result = "";

        String accessTokenUrl = String.format(QywxInnerConfig.MINI_ACCESS_TOKEN_URL, corpId, AGENT_SECRET);
        Map response = RestUtils.get(accessTokenUrl);

        //获取错误日志
        if (response.containsKey("errcode") && (Integer) response.get("errcode") != 0) {
            logger.error(response.toString());
        } else {
            result = (String) response.get("access_token");
        }
        return result;
    }
}

3.4. 工具类

RestUtils

package com.gblfy.qywxin.utils;

import com.alibaba.fastjson.JSONObject;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.*;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Objects;

@Configuration
public class RestUtils {

    private static final RestTemplate restTemplate = new RestTemplate();

    public static JSONObject get(String url, Map<String,String> urlParams){
        return get(urlToUri(url,urlParams));
    }

    //在处理企业微信某些参数时有问题
    public static JSONObject get(String url){
        return get(URI.create(url));
    }

    private static JSONObject get(URI uri){
        ResponseEntity<JSONObject> responseEntity =restTemplate.getForEntity(uri,JSONObject.class);
        serverIsRight(responseEntity);   //判断服务器返回状态码
        return responseEntity.getBody();
    }

    public static JSONObject post(String url,Map<String,String> urlParams,JSONObject json){
        //组装url
        return post(urlToUri(url,urlParams),json);
    }

    public static JSONObject post(String url,JSONObject json){
        //组装urL
        return post(URI.create(url),json);
    }

    private static JSONObject post(URI uri,JSONObject json){
        //组装url
        //设置提交json格式数据
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<JSONObject> request = new HttpEntity(json, headers);
        ResponseEntity<JSONObject> responseEntity = restTemplate.postForEntity(uri,request,JSONObject.class);
        serverIsRight(responseEntity);  //判断服务器返回状态码
        return responseEntity.getBody();
    }

    private static URI urlToUri(String url,Map<String,String> urlParams){
        //设置提交json格式数据
        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
        for(Map.Entry<String,String> entry : urlParams.entrySet())  {
            uriBuilder.queryParam((String)entry.getKey(),  (String) entry.getValue()) ;
        }
        return  uriBuilder.build(true).toUri();
    }

    public static JSONObject upload(String url,MultiValueMap formParams){
        //设置表单提交
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(formParams, headers);
        ResponseEntity<JSONObject> responseEntity = restTemplate.postForEntity(url,request,JSONObject.class);
        serverIsRight(responseEntity);  //判断服务器返回状态码
        return responseEntity.getBody();
    }

    public static String download(String url,String targetPath) throws IOException {

        ResponseEntity<byte[]> rsp = restTemplate.getForEntity(url, byte[].class);
        if(rsp.getStatusCode() != HttpStatus.OK){
            System.out.println("文件下载请求结果状态码:" + rsp.getStatusCode());
        }
        // 将下载下来的文件内容保存到本地
        Files.write(Paths.get(targetPath), Objects.requireNonNull(rsp.getBody()));
        return targetPath;

    }

    public static byte[] dowload(String url){
        ResponseEntity<byte[]> rsp = restTemplate.getForEntity(url, byte[].class);
        return rsp.getBody();
    }

    private static void serverIsRight(ResponseEntity responseEntity){
        if(responseEntity.getStatusCodeValue()==200){
//            System.out.println("服务器请求成功:{}"+responseEntity.getStatusCodeValue());
        }else {
            System.out.println("服务器请求异常:{}"+responseEntity.getStatusCodeValue());
        }
    }


}

JWTUtils

package com.gblfy.qywxin.utils;

import com.gblfy.qywxin.vo.QywxInnerUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

public class JWTUtils {

    private static final long EXPIRE = 60000 * 60 * 24 * 7;
    private static final String SECRET = "tobdev.com";


    private static final String TOKEN_PREFIX = "tobdev";

    private static final String SUBJECT = "tobdev";

    /**
     * 生成jwt token
     *
     * @param user
     * @return
     */
    public static String geneJsonWebToken(QywxInnerUser user) {
        String token = Jwts.builder().setSubject(SUBJECT)
                .claim("corp_id", user.getCorpId())
                .claim("user_id", user.getUserId())
                .claim("user_name", user.getName())
                .claim("mobile", user.getMobile())
                .claim("qr_code", user.getQrCode())
                .claim("user_type", user.getUserType())
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                .signWith(SignatureAlgorithm.HS256, SECRET).compact();
        token = TOKEN_PREFIX + token;
        return token;
    }

    /**
     * 校验token是否合法
     *
     * @param token
     * @return
     */
    public static Claims checkJWT(String token) {
        try {
            final Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();
            return claims;
        } catch (Exception e) {
            return null;
        }
    }
}

3.5. vo对象
package com.gblfy.qywxin.vo;

/**
 * 返回封装对象
 *
 * @author gblfy
 * @date 2022-01-12
 */
public class JsonData {
    /**
     * 业务上的成功或失败
     */
    private boolean success = true;
    private Integer code;
    private String msg;
    private Object data;

    public JsonData() {

    }

    public JsonData(Integer code, Object data, String msg,boolean success) {
        this.code = code;
        this.data = data;
        this.msg = msg;
        this.success = success;

    }

    public static JsonData buildSuccess() {
        return new JsonData(0, null, null,true);
    }

    public static JsonData buildSuccess(Object data) {
        return new JsonData(0, data, null,true);
    }

    public static JsonData buildError(String msg) {
        return new JsonData(-1, null, msg,false);
    }

    public static JsonData buildError(Integer code, String msg) {
        return new JsonData(code, null, msg,false);
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
    public boolean getSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }
}

其他相关类,小伙伴们看源码吧,见2.3小节

四、调试部分
4.1. 模式切换

在这里插入图片描述

4.2. api执行流程

在这里插入图片描述

4.3. 报文赏评

调用login的api返回报文

{
    "code": "uXGXKHjUcNLbtO0sBNylDpOHmpgmXTnNkDLVMYWu7MQ"
}

调用后端获取用户信息接口返回的报文

{
    "success": true,
    "code": 0,
    "msg": null,
    "data": {
        "corpid": "wwea98220fdcd8a38d",
        "deviceid": "",
        "errcode": 0,
        "errmsg": "ok",
        "session_key": "qz2VF4V3RTagW+awOAZdpA==",
        "token": "tobdeveyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0b2JkZXYiLCJjb3JwX2lkIjoid3cxN2Y4ZDEwNzgzNDk0NTg0IiwiaWF0IjoxNjQyNDI3ODUyLCJleHAiOjE2NDMwMzI2NTJ9.965kwCYUt6h-BeCA-WUaf20LrHpMvzX8WYigNlkJJIQ",
        "userid": "ZeXin"
    }
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gblfy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值