Enterprise WeChat custom application page authorization process

1. Background

       Recently received a project, the original project team (product, technology) has been disbanded, the handover status is unknown, and no one took over. It just happened that the business I was in charge of had a half-centre relationship with these projects. When other teams found me, I was also confused, asking three questions, and I didn't have the source code. So I asked the department manager for help (gitlab permission, look for the project of the entire company), after finding the source code of the project, fuck, the backend is PHP, but I told the relevant people that it needed to be refactored. I studied the relevant pages and PHP source code by myself, figured out what business was involved, pondered for three or two days, and finally knew why. . .

Two, development ideas

  1. Configure the enterprise WeChat application and go to the enterprise WeChat backend to manage the configuration, as shown in the screenshot below:

 2. The page address , if the domain name access after deployment is: https://www.aaa.com/wp_wework/workphoto/home   , you need to configure this trusted domain name , find a custom application , and configure it as follows:

 3. Page authorization , the user can use the enterprise WeChat to operate the application page of the enterprise WeChat, and the page can obtain the user information. So what is the authorization relationship between them? This is the key point .

     1) Get the company's jsapi_ticket, the related operations are as follows: 

      A. Parameters involved: dto field

{

private String corpId;  // 企业微信ID
private String agentId; // 应用ID
private String url;   // 可信赖域名

}

public String getCorpTicket(String corpId, String agentId , QyAgentCommondUrlDTO dto) {
// 获取 redis 的缓存数据		
String res = repository.get(QYWEIXIN_JSAPI_TICKET_KEY+dto.getCorpId()+dto.getAgentId());
		String jsapi_ticket = "";
		if(StringUtil.isEmpty(res)){
            // 调用 企业微信的接口:获取企业的jsapi_ticket 
			String result = OAuthApi.getJsapiTicket().getJson();
			JSONObject resultJson = JSONObject.parseObject(result);
			if(resultJson.get("ticket") != null){
				jsapi_ticket = resultJson.getString("ticket");
				repository.setExpire(QYWEIXIN_JSAPI_TICKET_KEY+dto.getCorpId()+dto.getAgentId(),result,7200);
			}
		}else{
			JSONObject resJson = JSONObject.parseObject(res);
			jsapi_ticket = resJson.getString("ticket");
		}
		//生成的随机字符串
		String nonce_str = StringUtilsX.getRandomStringByLength(32);
		//时间戳
		Long timeStamp = System.currentTimeMillis() / 1000;
		String stringSignTemp = "jsapi_ticket="+jsapi_ticket+"&noncestr=" + nonce_str+"&timestamp=" + timeStamp
				+"&url="+dto.getUrl();

		String signature = StringUtilsX.getSha1(stringSignTemp);
		net.sf.json.JSONObject tickJson = new net.sf.json.JSONObject();
		tickJson.put("appId",dto.getCorpId());
		tickJson.put("timestamp",timeStamp);
		tickJson.put("nonceStr",nonce_str);
		tickJson.put("signature",signature);
		tickJson.put("isSuccess",Boolean.TRUE);
		tickJson.put("responseCode",0);
		tickJson.put("responseMsg","请求成功");
		logger.info("---getJsticket--results:"+tickJson);

		return tickJson.toString();
	}


// 加解密类
public class StringUtilsX {
    /**
     * StringUtils工具类方法 获取一定长度的随机字符串,范围0-9,a-z
     *
     * @return 一定长度的随机字符串
     */
    public static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    /**
     * sha1 加密
     * @param str
     * @return
     */
    public static String getSha1(String str){
        if(str==null||str.length()==0){
            return null;
        }
        char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9',
                'a','b','c','d','e','f'};
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
            mdTemp.update(str.getBytes("UTF-8"));

            byte[] md = mdTemp.digest();
            int j = md.length;
            char buf[] = new char[j*2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf);
        } catch (Exception e) {
            // TODO: handle exception
            return null;
        }
    }
}

Js processing front-end interface: This is mainly acquired companies jsapi_ticket  and jsapi_ticket acquisition applications , to authorize the interface. Note: wxCorpConfig, wxAgentConfig, currently use wxCorpConfig, wxAgentConfig is temporarily useless.

async function wxShareRequest({ url, title, desc, link, imgUrl, phone } = {}) {
    try {
        // 开发环境
        let domain = process.env.NODE_ENV == 'development' ? 'https://www.aaa.com/wp_wework/' : 'https://www.bbbb.com/wp_wework/';
        let wxCorpConfig = await getWxplatformCorpConfig()
        let wxAgentConfig = await getWxplatformAgentConfig()
        if (wxCorpConfig === false || wxAgentConfig === false) return
        wx.config({
            beta: true,// 必须这么写,否则wx.invoke调用形式的jsapi会有问题
            debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: wxCorpConfig.appId, // 必填,企业微信的corpID
            timestamp: wxCorpConfig.timestamp, // 必填,生成签名的时间戳
            nonceStr: wxCorpConfig.nonceStr, // 必填,生成签名的随机串
            signature: wxCorpConfig.signature, // 必填,签名,见 附录-JS-SDK使用权限签名算法
            jsApiList: ['openUserProfile','agentConfig', 'onMenuShareAppMessage', 'onMenuShareWechat', 'onMenuShareTimeline'] // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
        });

        wx.ready(function() {

            wx.onMenuShareAppMessage({
                title: '工作形象照', // 分享标题
                desc: '蓝月亮的小伙伴,快来制作你的专属企业微信头像吧!', //'快速制作企业微信头像 ', // 分享描述
                link: domain, // 分享链接;在微信上分享时,该链接的域名必须与企业某个应用的可信域名一致
                imgUrl: domain + (imgUrl || '/static/img/share.png'), // 分享图标
                success: function() {
                    // 用户确认分享后执行的回调函数
                },
                cancel: function() {
                    // 用户取消分享后执行的回调函数
                }
            });

            wx.onMenuShareWechat({
                title: '工作形象照', // 分享标题
                desc: '蓝月亮的小伙伴,快来制作你的专属企业微信头像吧!', // 分享描述
                link: domain, // 分享链接
                imgUrl: domain + (imgUrl || '/static/img/share.png'), // 分享图标
                success: function() {
                    // 用户确认分享后执行的回调函数
                },
                cancel: function() {
                    // 用户取消分享后执行的回调函数
                }
            });

            wx.onMenuShareTimeline({
                title: '工作形象照', // 分享标题
                link: domain, // 分享链接
                imgUrl: domain + (imgUrl || '/static/img/share.png'), // 分享图标
                success: function() {
                    // 用户确认分享后执行的回调函数
                },
                cancel: function() {
                    // 用户取消分享后执行的回调函数
                }
            });

        });
    } catch (error) {
        
    }
}

 2). Webpage authorization method, webpage authorization login , this is mainly to obtain user information, just like after we log in, there is a token, as shown in the figure below:

There are two steps here:

  The first step: Click on the application, the page jumps. In the initial process of the page , you need to configure the jump permissions . Here, the focus is on the routing jump settings, as follows:

重点:获取code ,既是:window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + global.AppId + '&redirect_uri=' + encodeURIComponent(global.domain + to.fullPath) + '&response_type=code&scope=snsapi_base&agentid='+global.agentId+'&state=STATE#wechat_redirect'

// 白名单
const whiteList = ['/login', '/register'] // no redirect whitelist
const agent = window.navigator.userAgent.toLowerCase();

// 全局路由卫士
router.beforeEach((to, from, next) => {

    // 设置页面title
    document.title = getPageTitle(to.meta.title);

    // 确定用户是否已登录(cookie中是否有token) getToken();
    const hasToken = getToken(); 
    if (hasToken) {
        next()
    } else {
        console.log(to)

        /* has no token*/
        // 在免登录白名单,直接进入
        if (whiteList.indexOf(to.path) !== -1) {
            next()
        } else {
            // 没有访问权限的其他页面被重定向到登录页面。
            // redirect 后携带登录后要访问的页面 to.fullPath 可将query中的参数一并带入
            // next(`/login?redirect=${encodeURIComponent(to.fullPath)}`);

            /**
             * 微信授权
             * @description 微信环境则走微信授权获取个人信息及支持微信支付
             */
            // 判断是否为微信环境 utils.isWechat
            if (agent.match(/MicroMessenger/i) == "micromessenger") {
                // 判断是否微信授权过
                // 判断是否有微信授权回调 code
                if (!to.query.code) {
                    window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + global.AppId + '&redirect_uri=' + encodeURIComponent(global.domain + to.fullPath) + '&response_type=code&scope=snsapi_base&agentid='+global.agentId+'&state=STATE#wechat_redirect'
                } else {
                    let corpId = global.AppId; // 企业微信ID
                    let agentId = global.agentId; // 应用ID
                    let param ={
                        corpId: corpId, 
                        agentId: agentId,
                        code: to.query.code.trim()
                    }
					// 通过code获取用户信息
                    authAction(param).then(response => {
                        if (response.data.success) {
                            let obj = response.data.data;
                            if (!obj){
                                console.log("后台返回为空的用户对象");
                                return ;
                            }
                            let item = {
                                name: obj.name,
                                employeeNo:obj.userid,
                                gender:obj.gender,
                                corpId: corpId,
                                agentId: agentId
                            }
                            let token = obj.userid;
                            setToken(token);
                            setUserInfo(item);
                        }
                        next('/');
                    }).catch(error => {
                        console.error(error)
                    })
                }
            } else {
                Toast({
                    message: '请在企业微信客户端打开',
                    forbidClick: true, // 禁用背景点击
                    duration: 2000
                });
            }

        }
    }

})

Step 2: Obtain user information. The method is: authAction   . The background here calls two methods: obtain member information according to code  and  read member   . The former obtains the enterprise WeChat employee number, and the latter obtains user information according to the employee number. At this point, the entire page is authorized successfully. The front end does a good job of caching user information.

Three, summary

  1. Authorization issues after clicking the application on the enterprise WeChat ( getting the enterprise's jsapi_ticket , webpage authorization login ), focusing on the page jump is the authorization of the route jump process.

  2. The authorization processing of the enterprise WeChat interface calls requires the configuration information of the enterprise WeChat application.

  3. The front-end page caches the user information after the user is authorized, and cookie is recommended.

  4. The article is relatively rough, aiming to briefly describe the page authorization ideas of enterprise WeChat custom applications. Simply put, which pages are authorized, what are the existing authorization interfaces, which parameters are passed, and what to pay attention to.

Guess you like

Origin blog.csdn.net/baidu_28068985/article/details/113174698
Recommended