寫在前面
在日常開發過程中我們難免會遇到需要網頁授權登入擷取使用者openId的情況,随着開發的深入我們會有很多網頁需要用到使用者的openId,而我們不可能每次都去寫一個授權登入的接口去比對每個網頁,為了減少我們重複的工作,本篇文章将分享一個所有網頁公共授權方案包括未配置的安全域名下的網頁。如有不足之處,可在評論區指出。
本次使用開發語言為java。使用架構springboot。
前期配置
我們都知道要想實作微信公衆号的網頁授權登入,需在公衆号管理背景“設定與開發”->“公衆号設定”->"功能設定"中設定網頁授權域名,如下圖所示
網頁授權域配置
但是微信官方将此域名配置限制為僅可設定兩個,那我們需要跳轉其他域名怎麼辦呢,其實很簡單,我們接着往下看!
授權流程
大家都知道微信網頁授權隻需要在確定微信公衆賬号擁有授權作用域(scope參數)的權限的前提下(已認證服務号,預設擁有 scope 參數中的snsapi_base和snsapi_userinfo 權限),引導關注者打開如下頁面:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
需要注意的是這裡的授權登入很有可能多次轉發,導緻code過期的情況,是以可以加入參數connect_redirect=1告訴微信僅跳轉一次
REDIRECT_URI就為我們的使用者确認授權後 微信轉發的位址 我們要實作公共網頁的授權登入就在這裡做文章
關于scope作用域這裡就不再過多地描述snsapi_base僅可以拿到戶的 openid,并且使用者是無感覺的,是靜默的。snsapi_userinfo可以拿到使用者的基本資訊,但不是無感覺的需要使用者手動确認,特殊情況除外(對于已關注公衆号的使用者,如果使用者從公衆号的會話或者自定義菜單進入本公衆号的網頁授權頁,即使是 scope 為snsapi_userinfo,也是靜默授權,使用者無感覺)。
實作代碼
/**
* 公共重定向
* @param url
* @param request
* @return
*/
@RequestMapping("/common")
public String authCommonUrl(String url, HttpServletRequest request)
try {
if (StringUtils.isEmpty(url)) {
return "/error";
}
return "redirect:https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + environment.getProperty("wechat.appId")
+ "&redirect_uri="
+ URLEncoder.encode(
environment.getProperty("wechat.baseRedirectUrl") + "/authcommonurl?url=" + URLEncoder.encode(url, "utf-8"),
"utf-8")
+ "&response_type=code&scope=snsapi_userinfo&connect_redirect=1&state=join#wechat_redirect";
} catch (Exception e) {
logger.error("重定向發生異常->RedirectController.authCommon:" + ParamsUtils.showParams(request), e);
return "/error";
}
}
可以看到我們将redirect_uri設定成了一個公共的擷取使用者資訊的接口位址,然後在該位址上傳入我們需要最終跳轉的url,這裡的url我們如果需要傳遞其他參數,也可以直接加在url上。這裡我們隻要保證redirect_uri在網頁授權的安全域名下,而url任意域名都可以啦。
擷取使用者資訊重定向url位址
/**
* 授權回調轉發
* @param url
* @param code
* @param request
* @return
*/
@SuppressWarnings({ "unchecked" })
@RequestMapping(value = "/authcommonurl")
public String authCommon(String url, String code, HttpServletRequest request) {
HttpSession session = request.getSession();
try {
if (StringUtils.isEmpty(url)) {
return "/error";
}
if (StringUtils.isEmpty(code)) {
return "/error";
}
// 首先判斷session中是否存在使用者資訊,存在則跳過以下擷取使用者資訊方法,不存在繼續執行
String sessionId = session.getId();
CacheObject<JSONObject> cache = MapCacheManager.getInstance().getCache(sessionId);
JSONObject userInfoJO = cache != null ? cache.getObject() : null;
if (userInfoJO == null || StringUtils.isEmpty(userInfoJO.optString("nickname", ""))) {// 裡面為整個網頁登入授權過程
// 調用擷取accessToken接口 擷取accessToken
String json = HttpsUtil.httpMethodGet(getAccessTokenUrl(code), "UTF-8");
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(json);
} catch (Exception e) {
logger.error("擷取授權accesstoken轉換json異常->NotStaticAuthReturnController.authHd:" + json, e);
}
if (!jsonObject.has("access_token")) {
return "/error";
}
String access_token = jsonObject.optString("access_token", "");
String openid = jsonObject.optString("openid", "");
// 得到擷取使用者資訊的連結
// 擷取使用者資訊接口 擷取使用者資訊
String userInfoJson = HttpsUtil.httpMethodGet(getUserinfoUrl(access_token, openid), "UTF-8");
try {
userInfoJO = new JSONObject(userInfoJson);
} catch (JSONException e) {
userInfoJO = new JSONObject();
logger.error("擷取使用者資訊轉換json異常->NotStaticAuthReturnController.authcommon:" + userInfoJson, e);
}
if (!userInfoJO.has("nickname")) {
return "/error";
}
userInfoJO.put("nickname", EmojiFilter.filterEmoji(userInfoJO.optString("nickname", "")));
cache = new CacheObject<>();
cache.setExpires_in(7200L);
cache.setObject(userInfoJO);
MapCacheManager.getInstance().putCache(sessionId, cache);
}
// System.out.println("使用者資訊:" + userInfoJO.toString());//輸出使用者資訊 測試用
String user_openid = userInfoJO.optString("openid", "");
if (StringUtils.isEmpty(user_openid)) {
return "/error";
}
return "redirect:" + url + (url.contains("?") ? "&" : "?") + "openId=" + user_openid;
} catch (Exception e) {
e.printStackTrace();
logger.error("微信授權異常->NotStaticAuthReturnController.authCommonurl:" + ParamsUtils.showParams(request), e);
return "/error";
}
}
這裡我們作用域是snsapi_userinfo有擷取使用者的基本資訊,若無需這些資訊,按需求删除代碼即可。
如有問題或不足之處可在評論區指出,覺得還行的看官動動小手幫忙點個贊吧!
祝大家健健康康,每天開開心心!