企業微信開發之授權登錄


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

 

 

使用OAuth2前須知

關於網頁授權的可信域名

REDIRECT_URL中的域名,需要先配置至應用的“可信域名”,否則跳轉時會提示“redirect_uri參數錯誤”。
要求配置的可信域名,必須與訪問鏈接的域名完全一致。舉個例子:

  • 假定重定向訪問的鏈接是:http://mail.qq.com:8080/cgi-bin/helloworld:
配置域名 是否正確 原因
mail.qq.com:8080 correct 配置域名與訪問域名完全一致
email.qq.com error 配置域名必須與訪問域名完全一致
support.mail.qq.com error 配置域名必須與訪問域名完全一致
*.qq.com error 不支持泛域名設置
mail.qq.com error 配置域名必須與訪問域名完全一致,包括端口號
  • 假定配置的可信域名是 mail.qq.com:
訪問鏈接 是否正確 原因
https://mail.qq.com/cgi-bin/helloworld correct 配置域名與訪問域名完全一致
http://mail.qq.com/cgi-bin/redirect correct 配置域名與訪問域名完全一致,與協議頭/鏈接路徑無關
https://exmail.qq.com/cgi-bin/helloworld error 配置域名必須與訪問域名完全一致

關於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
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

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

  如果對你有幫助,請打賞一下!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM