天天看點

企業微信開發之授權登入wechat_redirect 是 終端使用此參數判斷是否需要帶上身份資訊

以前寫過一篇公衆号的授權登入 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接入流程

企業微信開發之授權登入wechat_redirect 是 終端使用此參數判斷是否需要帶上身份資訊

使用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一起傳回

非企業成員授權時傳回示例如下:

"OpenId":"OPENID",

"DeviceId":"DEVICEID"

OpenId    非企業成員的辨別,對目前企業唯一

出錯傳回示例:

"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

喜歡的朋友可以關注下,粉絲也缺。