package com.ynxbd.wx.wxfactory; import com.ynxbd.common.bean.Patient; import com.ynxbd.common.bean.User; import com.ynxbd.common.helper.common.*; import com.ynxbd.common.helper.http.OkHttpHelper; import com.ynxbd.common.result.Result; import com.ynxbd.common.service.PatientService; import com.ynxbd.wx.config.WeChatConfig; import com.ynxbd.wx.wxfactory.bean.SnsOath2AccessToken; import com.ynxbd.wx.wxfactory.bean.SnsUserInfo; import com.ynxbd.wx.wxfactory.bean.auth.AuthData; import lombok.extern.slf4j.Slf4j; import okhttp3.FormBody; import okhttp3.RequestBody; import org.apache.commons.lang3.ObjectUtils; import org.ehcache.Cache; import javax.servlet.http.HttpServletRequest; 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; @Slf4j public class WxAuthHelper { private static final int SESSION_MAX_INACTIVE_INTERVAL = 60 * 60; // session最大存活时间 1H public static String auth(HttpServletRequest request, HttpServletResponse response, boolean isUserInfo) { String code = request.getParameter("code"); String state = request.getParameter("state"); // base64 String enuId = request.getParameter("enuId"); log.info("[授权] code={}, state={}, enuId={}", code, state, enuId); try { state = state == null ? "" : URLDecoder.decode(Base64Helper.decode(state), "UTF-8"); String enUnionId = null; String protocolState = null; if (!ObjectUtils.isEmpty(enuId)) { int index = enuId.indexOf("@protocolState="); if (index == -1) index = enuId.indexOf("%40protocolState="); // 防止数据转义失败 if (index != -1) { enUnionId = enuId.substring(0, index); protocolState = enuId.substring(index); } } log.info("[授权-解码] enUnionId={}, protocolState={}, state={}", enUnionId, protocolState, state); SnsOath2AccessToken snsToken = WxFactory.Base.OAuth().oauth2AccessToken(WeChatConfig.APP_ID, WeChatConfig.APP_SECRET, code); if (snsToken != null) { String openid = snsToken.getOpenid(); String unionId = snsToken.getUnionid(); if (unionId == null) { log.info("[测试] enUnionId={}", enUnionId); } if (openid != null) { HttpSession session = request.getSession(); session.setMaxInactiveInterval(SESSION_MAX_INACTIVE_INTERVAL); session.setAttribute("openid", openid); Cache cache = WxCacheHelper.getUserCacheManager(); if (WeChatConfig.isDevUser(openid) || !cache.containsKey(openid)) { User user = new User(); user.setUnionId(unionId); user.setOpenid(openid); user.setIsSnapShotUser(snsToken.getIsSnapShotUser()); user.setPatientList(new PatientService().queryPatientList(openid, unionId, true)); if (isUserInfo) { SnsUserInfo snsUser = WxFactory.Base.OAuth().snsUserInfo(snsToken.getAccessToken(), openid, "zh_CN", 3); if (snsUser != null) { user.setCountry(snsUser.getCountry()); user.setAvatar(snsUser.getHeadImgUrl()); user.setNickName(snsUser.getNickname_emoji()); user.setProvince(snsUser.getProvince()); user.setGenderByInt(snsUser.getSex()); user.setCity(snsUser.getCity()); user.setLanguage(snsUser.getLanguage()); } } cache.put(openid, user); } else { if (isUserInfo) { User user = cache.get(openid); if (user != null && user.getAvatar() == null && user.getNickName() == null) { SnsUserInfo snsUser = WxFactory.Base.OAuth().snsUserInfo(snsToken.getAccessToken(), openid, "zh_CN", 3); if (snsUser != null) { user.setAvatar(snsUser.getHeadImgUrl()); user.setNickName(snsUser.getNickname_emoji()); user.setGenderByInt(snsUser.getSex()); } } } } } } if (WeChatConfig.HAS_HTTPS_BY_BASE_URL) { // 强制为https String httpsURL = URLHelper.URLToHttps(state); state = httpsURL == null ? "" : httpsURL; } if (state.contains(".html")) { // 网页授权配置 return state; } else { String baseUrl = WeChatConfig.getBaseURL(); if (baseUrl != null && state.contains(baseUrl)) { return state; } } } catch (Exception e) { log.error("[微信][获取重定向链接异常]{}", e.getMessage()); } return null; } public static Result isAuth(HttpServletRequest request, boolean isPayOAuth) throws Exception { 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 deState = URLDecoder.decode(Base64Helper.decode(state), "UTF-8"); if (WeChatConfig.IS_ENABLE_GMC && !WeChatConfig.IS_GMC_SERVER && !isPayOAuth) { // 开启医共体开关 & 不是医共体主服务器 & 不是支付授权 try { // 请求转发 String serverDomain = WeChatConfig.getDomain(false, false); if (deState != null && serverDomain != null && !deState.contains(serverDomain)) { return Result.error("授权域名不匹配"); } RequestBody requestBody = new FormBody.Builder() .add("token", token) .add("state", state) .add("isUserInfo", isUserInfo) .add("enuId", enuId) .add("protocolState", protocolState) .build(); log.info("[认证请求转发] URL:[{}]", WeChatConfig.getGMCAuthDomain(isHttpsWithProxy(request), true)); String data = OkHttpHelper.post(WeChatConfig.getGMCAuthDomain(isHttpsWithProxy(request), true) + "wx_auth/is_auth", requestBody); return Result.dataToResult(data, true); } catch (Exception e) { return Result.error(e); } } boolean isFindUserInfo = ("true".equals(isUserInfo)); AuthData authData = new AuthData(); String cacheOpenid = authData.decodeToken(token, WeChatConfig.APP_ID); if (cacheOpenid != null) { log.info("[微信token认证] token={}, openid={}", token, cacheOpenid); User user = WxCacheHelper.getCacheUser(cacheOpenid); List patients; if (user == null) { patients = new PatientService().queryPatientList(cacheOpenid, null, true); Cache cache = WxCacheHelper.getUserCacheManager(); User addCache = new User(); addCache.setOpenid(cacheOpenid); addCache.setUnionId(authData.getUnionId()); addCache.setAvatar(authData.getAvatar()); addCache.setNickName(authData.getNickName()); addCache.setPatientList(patients); cache.put(cacheOpenid, addCache); } else { patients = user.getPatientList(); } Map map = new HashMap<>(); map.put("openid", cacheOpenid); map.put("token", token); map.put("enOpenId", AesWxHelper.encode(cacheOpenid, true)); map.put("enUnionId", AesWxHelper.encode(authData.getUnionId(), true)); map.put("date", new Date()); map.put("avatar", authData.getAvatar()); map.put("nickName", authData.getNickName()); map.put("patients", CodeHelper.get28UUID() + Base64Helper.encode(URLEncoder.encode(JsonHelper.toJsonString(patients), "UTF-8"))); map.put("enParams", AesMicroHelper.encode(cacheOpenid)); return Result.success(map); } HttpSession session = request.getSession(); Object openid = session.getAttribute("openid"); if (openid != null) { log.info("[微信认证]openid={}", openid); User user = WxCacheHelper.getCacheUser((String) openid); if (user == null) { return Result.success(getAuthUrl(request, state, isFindUserInfo, enuId, protocolState)); } if (isFindUserInfo) { // 更换授权模式,需更新信息 if (user.getNickName() == null || user.getAvatar() == null) { return Result.success(getAuthUrl(request, state, true, enuId, protocolState)); } } Map map = new HashMap<>(); map.put("openid", openid); map.put("token", new AuthData().createToken(WeChatConfig.APP_ID, openid.toString(), user.getUnionId(), user.getAvatar(), user.getNickName())); map.put("enOpenId", AesWxHelper.encode(openid.toString(), true)); map.put("enUnionId", AesWxHelper.encode(user.getUnionId(), true)); map.put("date", new Date()); map.put("avatar", user.getAvatar()); map.put("nickName", user.getNickName()); map.put("patients", CodeHelper.get28UUID() + Base64Helper.encode(URLEncoder.encode(JsonHelper.toJsonString(user.getPatientList()), "UTF-8"))); map.put("enParams", AesMicroHelper.encode(openid.toString())); return Result.success(map); } return Result.success(getAuthUrl(request, state, isFindUserInfo, enuId, protocolState)); } 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 protocolState) { // StringBuffer url = request.getRequestURL(); // String baseUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).append(request.getServletContext().getContextPath()).append("/").toString(); if (state == null) { return null; } String api = isFindUserInfo ? "u_auth" : "b_auth"; String scope = isFindUserInfo ? "snsapi_userinfo" : "snsapi_base"; state = OAUTH_URL + WeChatConfig.getBaseURL(WeChatConfig.HAS_HTTPS_BY_BASE_URL || isHttpsWithProxy(request)) + "wx_auth/" + api + "?state=" + state + "&response_type=code" + "&scope=" + scope + "&forcePopup=true" + "&enuId=" + (enuId == null ? "" : enuId) + (protocolState == null ? "" : ("%40protocolState=" + protocolState)) + "#wechat_redirect"; return Base64Helper.encode(state); } // 是否为https请求 public static boolean isHttpsWithProxy(HttpServletRequest request) { // 优先检查代理头(适用于反向代理场景) String forwardedProto = request.getHeader("X-Forwarded-Proto"); if (forwardedProto != null) { return "https".equalsIgnoreCase(forwardedProto); } // 未经过代理,直接检查原生请求 return request.isSecure(); } // // 医共体开启 & 不是支付授权 // private static boolean isAuthGMC(boolean isPayOAuth) { // return WeChatConfig.IS_ENABLE_GMC && !isPayOAuth; // } // private static String getOAuthURL(HttpServletRequest request, boolean isPayOAuth) { // boolean isHttps = WeChatConfig.HAS_HTTPS_BY_BASE_URL || isHttpsWithProxy(request); // return isAuthGMC(isPayOAuth) // ? "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + WeChatConfig.GMC_AUTH_APP_ID + "&redirect_uri=" + WeChatConfig.getGMCAuthDomain(isHttps, true) // : "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + WeChatConfig.APP_ID + "&redirect_uri=" + WeChatConfig.getBaseURL(isHttps); // } // private static SnsOath2AccessToken getOath2AccessToken(String code, boolean isPayOAuth) { // if (isAuthGMC(isPayOAuth)) { // return WxFactory.Base.OAuth().oauth2AccessToken(WeChatConfig.GMC_AUTH_APP_ID, WeChatConfig.GMC_AUTH_APP_SECRET, code); // } // return WxFactory.Base.OAuth().oauth2AccessToken(WeChatConfig.APP_ID, WeChatConfig.APP_SECRET, code); // } // // 获取重定向链接 // private static String getAuthDomain(HttpServletRequest request, boolean isPayOAuth) { // if (isAuthGMC(isPayOAuth)) { // return WeChatConfig.getGMCAuthDomain(true, false); // 强制为https // } // return WeChatConfig.getDomain(WeChatConfig.HAS_HTTPS_BY_BASE_URL || isHttpsWithProxy(request)); // 配置中baseURL有"https"时优先级最高 ["@protocol=1"为https;"@protocol=0"为默认的http;] // } }