|
|
|
|
@ -19,36 +19,43 @@ import javax.servlet.http.HttpServletResponse; |
|
|
|
|
import javax.servlet.http.HttpSession; |
|
|
|
|
import java.net.URLDecoder; |
|
|
|
|
import java.net.URLEncoder; |
|
|
|
|
import java.util.Date; |
|
|
|
|
import java.util.HashMap; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Map; |
|
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
|
|
@Slf4j |
|
|
|
|
public class WxAuthHelper { |
|
|
|
|
private static final int SESSION_MAX_INACTIVE_INTERVAL = 60 * 60; // session最大存活时间 1H
|
|
|
|
|
|
|
|
|
|
private static final String P_PREFIX = "_@"; // 前缀
|
|
|
|
|
private static final String P_SUFFIX = ":"; // 后缀
|
|
|
|
|
|
|
|
|
|
private static final String AUTH_SESSION_ID_NAME = "SID"; |
|
|
|
|
private static final String UNION_ID_NAME = "UID"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static String auth(HttpServletRequest request, HttpServletResponse response, boolean isUserInfo) { |
|
|
|
|
String code = request.getParameter("code"); |
|
|
|
|
String state = request.getParameter("state"); // base64
|
|
|
|
|
String params = request.getParameter("params"); |
|
|
|
|
Map<String, String> paramsMap = getParamsMap(request.getParameter("p")); |
|
|
|
|
|
|
|
|
|
log.info("[授权] code={}, state={}, params={}", code, state, params); |
|
|
|
|
log.info("[授权] code={}, state={}, paramsMap={}", code, state, JsonHelper.toJsonString(paramsMap)); |
|
|
|
|
try { |
|
|
|
|
state = state == null ? "" : URLDecoder.decode(Base64Helper.decode(state), "UTF-8"); |
|
|
|
|
String enUnionId = null; |
|
|
|
|
String authSessionId = null; |
|
|
|
|
|
|
|
|
|
if (!ObjectUtils.isEmpty(params)) { |
|
|
|
|
int index = params.indexOf("@SID="); |
|
|
|
|
if (index == -1) index = params.indexOf("%40SID="); // 防止数据转义失败
|
|
|
|
|
if (index != -1) { |
|
|
|
|
enUnionId = params.substring(0, index); |
|
|
|
|
authSessionId = params.substring(index); |
|
|
|
|
authSessionId = AesWxHelper.decode(authSessionId); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
log.info("[授权-解码] enUnionId={}, authSessionId={}, state={}", enUnionId, authSessionId, state); |
|
|
|
|
String enUnionId = paramsMap.get(UNION_ID_NAME); |
|
|
|
|
String enAuthSessionId = paramsMap.get(AUTH_SESSION_ID_NAME); |
|
|
|
|
String authSessionId = AesWxHelper.decode(enAuthSessionId); |
|
|
|
|
|
|
|
|
|
paramsMap.get(AUTH_SESSION_ID_NAME); |
|
|
|
|
|
|
|
|
|
// if (!ObjectUtils.isEmpty(params)) {
|
|
|
|
|
// int index = params.indexOf("@" + AUTH_SESSION_ID_NAME + ":");
|
|
|
|
|
// if (index == -1) index = params.indexOf("%40" + AUTH_SESSION_ID_NAME + ":"); // 防止数据转义失败
|
|
|
|
|
// if (index != -1) {
|
|
|
|
|
// enUnionId = params.substring(0, index);
|
|
|
|
|
// authSessionId = params.substring(index);
|
|
|
|
|
// authSessionId = AesWxHelper.decode(authSessionId);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
log.info("[授权-解码] enUnionId={}, enAuthSessionId={}, authSessionId={}, state={}", enUnionId, enAuthSessionId, authSessionId, state); |
|
|
|
|
|
|
|
|
|
SnsOath2AccessToken snsToken = WxFactory.Base.OAuth().oauth2AccessToken(WeChatConfig.APP_ID, WeChatConfig.APP_SECRET, code); |
|
|
|
|
log.info("[授权-用户]snsToken={}", JsonHelper.toJsonString(snsToken)); |
|
|
|
|
@ -127,15 +134,15 @@ public class WxAuthHelper { |
|
|
|
|
String token = request.getParameter("token"); // 前端缓存
|
|
|
|
|
String state = request.getParameter("state"); |
|
|
|
|
String isUserInfo = request.getParameter("isUserInfo"); |
|
|
|
|
// String protocolState = request.getParameter("protocolState");
|
|
|
|
|
String enUID = ParamHelper.filterParamNull(request.getParameter("enUID"), ""); |
|
|
|
|
String UID = ParamHelper.filterParamNull(request.getParameter(UNION_ID_NAME), ""); |
|
|
|
|
String deState = URLDecoder.decode(Base64Helper.decode(state), "UTF-8"); |
|
|
|
|
|
|
|
|
|
String authSessionId = null; |
|
|
|
|
if (WeChatConfig.IS_ENABLE_GMC && WeChatConfig.IS_GMC_SERVER && !isPayOAuth) { // 开启医共体开关 & 是医共体主服务器 & 不是支付授权
|
|
|
|
|
authSessionId = AesWxHelper.decode(request.getHeader("AID")); |
|
|
|
|
authSessionId = AesWxHelper.decode(request.getHeader(AUTH_SESSION_ID_NAME)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
log.info("[is_auth]token={}, state={}, isUserInfo={}, authSessionId={}, enUID={}, deState={}", token, state, isUserInfo, authSessionId, enUID, deState); |
|
|
|
|
log.warn("[授权is_auth] token={}, state={}, isUserInfo={}, authSessionId={}, UID={}, deState={}", token, state, isUserInfo, authSessionId, UID, deState); |
|
|
|
|
if (WeChatConfig.IS_ENABLE_GMC && !WeChatConfig.IS_GMC_SERVER && !isPayOAuth) { // 开启医共体开关 & 不是医共体主服务器 & 不是支付授权
|
|
|
|
|
try { // 请求转发
|
|
|
|
|
String serverDomain = WeChatConfig.getDomain(false, false); |
|
|
|
|
@ -151,11 +158,10 @@ public class WxAuthHelper { |
|
|
|
|
params.put("token", token); |
|
|
|
|
params.put("state", state); |
|
|
|
|
params.put("isUserInfo", isUserInfo); |
|
|
|
|
params.put("enuId", enUID); |
|
|
|
|
// params.put("protocolState", protocolState);
|
|
|
|
|
params.put(UNION_ID_NAME, UID); |
|
|
|
|
}, headers -> { |
|
|
|
|
if (!ObjectUtils.isEmpty(sessionId)) { |
|
|
|
|
headers.add("AID", AesWxHelper.encode(sessionId)); |
|
|
|
|
headers.add(AUTH_SESSION_ID_NAME, AesWxHelper.encode(WeChatConfig.APP_ID + ":" + sessionId)); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
Result result = Result.dataToResult(data, true); |
|
|
|
|
@ -206,17 +212,17 @@ public class WxAuthHelper { |
|
|
|
|
Object sessionOpenId = session.getAttribute("openid"); |
|
|
|
|
String openid = sessionOpenId == null ? null : sessionOpenId.toString(); |
|
|
|
|
|
|
|
|
|
log.info("[微信认证]获取 openid={}, authSessionId={}", openid, authSessionId); |
|
|
|
|
log.info("[微信认证] openid={}, authSessionId={}", openid, authSessionId); |
|
|
|
|
if (!ObjectUtils.isEmpty(authSessionId) && ObjectUtils.isEmpty(openid)) { |
|
|
|
|
openid = WxCacheHelper.getOpenIdByAIDCache(authSessionId); |
|
|
|
|
log.info("[微信AID认证]openid={}", openid); |
|
|
|
|
log.warn("[微信AID认证]openid={}", openid); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (openid != null) { |
|
|
|
|
log.info("[微信认证]openid={}", openid); |
|
|
|
|
User user = WxCacheHelper.getCacheUser(openid); |
|
|
|
|
if (user == null) { |
|
|
|
|
return Result.success(getAuthUrl(request, state, isFindUserInfo, enUID, authSessionId)); |
|
|
|
|
return Result.success(getAuthUrl(request, state, isFindUserInfo, UID, authSessionId)); |
|
|
|
|
} else { |
|
|
|
|
if (ObjectUtils.isEmpty(openid)) { |
|
|
|
|
openid = user.getOpenid(); // sessionId认证openid补充
|
|
|
|
|
@ -225,7 +231,7 @@ public class WxAuthHelper { |
|
|
|
|
|
|
|
|
|
if (isFindUserInfo) { // 更换授权模式,需更新信息
|
|
|
|
|
if (user.getNickName() == null || user.getAvatar() == null) { |
|
|
|
|
return Result.success(getAuthUrl(request, state, true, enUID, authSessionId)); |
|
|
|
|
return Result.success(getAuthUrl(request, state, true, UID, authSessionId)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -242,12 +248,12 @@ public class WxAuthHelper { |
|
|
|
|
return Result.success(map); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return Result.success(getAuthUrl(request, state, isFindUserInfo, enUID, authSessionId)); |
|
|
|
|
return Result.success(getAuthUrl(request, state, isFindUserInfo, UID, authSessionId)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static final String OAUTH_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + WeChatConfig.APP_ID + "&redirect_uri="; |
|
|
|
|
|
|
|
|
|
private static String getAuthUrl(HttpServletRequest request, String state, boolean isFindUserInfo, String enUID, String SID) { |
|
|
|
|
private static String getAuthUrl(HttpServletRequest request, String state, boolean isFindUserInfo, String UID, String SID) { |
|
|
|
|
// StringBuffer url = request.getRequestURL();
|
|
|
|
|
// String baseUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).append(request.getServletContext().getContextPath()).append("/").toString();
|
|
|
|
|
if (state == null) { |
|
|
|
|
@ -257,23 +263,25 @@ public class WxAuthHelper { |
|
|
|
|
String api = isFindUserInfo ? "u_auth" : "b_auth"; |
|
|
|
|
String scope = isFindUserInfo ? "snsapi_userinfo" : "snsapi_base"; |
|
|
|
|
|
|
|
|
|
String enSID = ""; |
|
|
|
|
UID = toURLParam(UNION_ID_NAME, UID); |
|
|
|
|
String enSID = toURLParam(AUTH_SESSION_ID_NAME, AesWxHelper.encode(SID, true)); |
|
|
|
|
|
|
|
|
|
String params = enSID + UID; |
|
|
|
|
try { |
|
|
|
|
enSID = (SID == null ? "" : ("%40SID=" + URLEncoder.encode(AesWxHelper.encode(SID), "UTF-8"))); |
|
|
|
|
params = ObjectUtils.isEmpty(params) ? "" : URLEncoder.encode(params, "UTF-8"); |
|
|
|
|
log.warn("[认证链接参数] params={}", params); |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
log.error(e.getMessage()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
log.info("[认证链接] enSID={}, SID={}", enSID, SID); |
|
|
|
|
|
|
|
|
|
state = OAUTH_URL + WeChatConfig.getBaseURL(WeChatConfig.HAS_HTTPS_BY_BASE_URL || isHttpsWithProxy(request)) + |
|
|
|
|
"wx_auth/" + api + |
|
|
|
|
"?state=" + state + |
|
|
|
|
"?p=" + params + |
|
|
|
|
"&response_type=code" + |
|
|
|
|
"&scope=" + scope + "&forcePopup=true" + |
|
|
|
|
"¶ms=" + (enUID == null ? "" : enUID) + |
|
|
|
|
enSID + |
|
|
|
|
"&scope=" + scope + |
|
|
|
|
"&forcePopup=true" + |
|
|
|
|
"&state=" + state + // state位置固定
|
|
|
|
|
"#wechat_redirect"; |
|
|
|
|
log.warn("[认证授权链接]state={}", state); |
|
|
|
|
return Base64Helper.encode(state); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -289,6 +297,41 @@ public class WxAuthHelper { |
|
|
|
|
return request.isSecure(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static String toURLParam(String key, String val) { |
|
|
|
|
if (ObjectUtils.isEmpty(val)) return ""; |
|
|
|
|
return P_PREFIX + key + P_SUFFIX + val; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static Map<String, String> getParamsMap(String params) { |
|
|
|
|
Map<String, String> paramsMap = new HashMap<>(); |
|
|
|
|
try { |
|
|
|
|
if (ObjectUtils.isEmpty(params)) { |
|
|
|
|
return paramsMap; |
|
|
|
|
} |
|
|
|
|
params = URLDecoder.decode(params, "UTF-8"); |
|
|
|
|
String[] paramsArr = params.split(P_PREFIX); |
|
|
|
|
String key, val; |
|
|
|
|
String[] keyValueArr; |
|
|
|
|
for (String paramItem : paramsArr) { |
|
|
|
|
if (paramItem.isEmpty()) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
keyValueArr = paramItem.split(P_SUFFIX, 2); // 分割成最多两部分
|
|
|
|
|
if (keyValueArr.length == 2) { |
|
|
|
|
key = keyValueArr[0]; |
|
|
|
|
val = keyValueArr[1]; |
|
|
|
|
val = ParamHelper.filterParamNull(val, null); |
|
|
|
|
if (val != null) { |
|
|
|
|
paramsMap.put(key, val); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
log.error(e.getMessage()); |
|
|
|
|
} |
|
|
|
|
return paramsMap; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // 医共体开启 & 不是支付授权
|
|
|
|
|
// private static boolean isAuthGMC(boolean isPayOAuth) {
|
|
|
|
|
|