之前寫過一篇公衆號的受權登陸https://blog.csdn.net/dsn727455218/article/details/65630151,今天給你們分享一下企業微信的受權登陸。java
大體都差很少流程web
注意事項:spring
1.網頁受權及JS-SDK須要在企業微信上配置可信域名json
2.企業微信受權登陸裏面填寫你的可信域名c#
調用流程爲:
A) 用戶訪問第三方服務,第三方服務經過構造OAuth2連接(參數包括當前第三方服務的身份ID,以及重定向URI),將用戶引導到認證服務器的受權頁
B) 用戶選擇是否贊成受權
C) 若用戶贊成受權,則認證服務器將用戶重向到第一步指定的重定向URI,同時附上一個受權碼。
D) 第三方服務收到受權碼,帶上受權碼來源的重定向URI,向認證服務器申請憑證。
E) 認證服務器檢查受權碼和重定向URI的有效性,經過後頒發AccessToken(調用憑證)api
企業微信OAuth2接入流程緩存
REDIRECT_URL中的域名,須要先配置至應用的「可信域名」,不然跳轉時會提示「redirect_uri參數錯誤」。
要求配置的可信域名,必須與訪問連接的域名徹底一致。舉個例子:服務器
配置域名 | 是否正確 | 緣由 |
---|---|---|
mail.qq.com:8080 | ![]() |
配置域名與訪問域名徹底一致 |
email.qq.com | ![]() |
配置域名必須與訪問域名徹底一致 |
support.mail.qq.com | ![]() |
配置域名必須與訪問域名徹底一致 |
*.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信息,若是須要獲取用戶的更多信息能夠調用 通信錄管理 - 成員接口 來獲取。微信
經過OAuth2.0驗證接口獲取成員身份會有必定的時間開銷。對於頻繁獲取成員身份的場景,建議採用以下方案:
一、企業應用中的URL連接直接填寫企業本身的頁面地址
二、成員操做跳轉到步驟1的企業頁面時,企業後臺校驗是否有標識成員身份的cookie信息,此cookie由企業生成
三、若是沒有匹配的cookie,則重定向到OAuth驗證連接,獲取成員的身份信息後,由企業後臺植入標識成員身份的cookie信息
四、根據cookie獲取成員身份後,再進入相應的頁面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
若是對你有幫助,請打賞一下!!!