First of all, we need to understand the request process of the h5 page
at the first authorization
client request url
WeChat returns a code to the client
When the user clicks to approve the authorization, he takes the code and obtains the access_token and openId. The code is valid for 5 minutes, and the access_token is a globally unique ticket with a validity period of two hours. When it expires, it needs to be re-acquired
openid is a unique identifier of the user in this public service number
access_token is a credential when you go to the WeChat server to request basic user information
Simply put, the client ---- WeChat server ---- third-party server
interaction between the three
First, create a new WeChat data storage class WeixinOauth2Token
package com.wonder.entity; /** * Created by Guozhijie on 2016/10/27. */ public class WeixinOauth2Token { // Web page authorization interface call credentials private String accessToken; // how long the certificate is valid private int expiresIn; // used to refresh credentials private String refreshToken; // user ID private String openId; // user authorization scope private String scope; public String getAccessToken() { return accessToken; } public void setAccessToken(String accessToken) { this.accessToken = accessToken; } public int getExpiresIn() { return expiresIn; } public void setExpiresIn(int expiresIn) { this.expiresIn = expiresIn; } public String getRefreshToken () { return refreshToken; } public void setRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } public String getOpenId() { return openId; } public void setOpenId(String openId) { this.openId = openId; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } }
WeChat user information class weixinUserInfo
package com.wonder.entity; /** * Created by Guozhijie on 2016/10/27. */ public class WeixinUserInfo { // user's ID private String openId; // Follow status (1 means follow, 0 means not follow), you can't get the rest of the information when you don't follow private int subscribe; // User attention time, timestamp. If the user has followed many times, take the last follow time private String subscribeTime; // Nick name private String nickname; // User's gender (1 is male, 2 is female, 0 is unknown) private int sex; // user's country private String country; // user's province private String province; // user's city private String city; // User's language, Simplified Chinese is zh_CN private String language; // profile picture private String headImgUrl; public String getOpenId() { return openId; } public void setOpenId(String openId) { this.openId = openId; } public int getSubscribe() { return subscribe; } public void setSubscribe(int subscribe) { this.subscribe = subscribe; } public String getSubscribeTime() { return subscribeTime; } public void setSubscribeTime(String subscribeTime) { this.subscribeTime = subscribeTime; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } public String getHeadImgUrl() { return headImgUrl; } public void setHeadImgUrl(String headImgUrl) { this.headImgUrl = headImgUrl; } }
Server Certificate Passport Class
package com.wonder.Util; import javax.net.ssl.X509TrustManager; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; /** * Created by Guozhijie on 2016/10/27. */ public class MyX509TrustManager implements X509TrustManager { // Check client certificate public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } // Check server side certificate public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } // Returns an array of trusted X509 certificates public X509Certificate[] getAcceptedIssuers() { return null; } }
Request tool class
package com.wonder.Util; import com.wonder.entity.WeixinOauth2Token; import net.sf.json.JSONException; import net.sf.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.servlet.http.HttpServletRequest; import java.io. *; import java.net.ConnectException; import java.net.URL; /** * Created by Guozhijie on 2016/10/27. */ public class CommonUtil { private static Logger log = LoggerFactory.getLogger(CommonUtil.class); // Credential acquisition (GET) public final static String token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; /** * Send https request * * @param requestUrl request address * @param requestMethod request method (GET, POST) * @param outputStr Submitted data * @return JSONObject (get the attribute value of the json object by JSONObject.get(key)) */ public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; try { // Create an SSLContext object and initialize it with our specified trust manager TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // Get the SSLSocketFactory object from the above SSLContext object SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); // Set the request method (GET/POST) conn.setRequestMethod(requestMethod); // Write data to the output stream when outputStr is not null if (null != outputStr) { OutputStream outputStream = conn.getOutputStream(); // Note the encoding format outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // Read the return content from the input stream InputStream inputStream = conn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } // release resources bufferedReader.close(); inputStreamReader.close(); inputStream.close(); inputStream = null; conn.disconnect(); jsonObject = JSONObject.fromObject(buffer.toString()); } catch (ConnectException ce) { log.error("Connection timed out: {}", ce); } catch (Exception e) { log.error("https request exception: {}", e); } return jsonObject; } /** * Get interface access credentials * * @param appid credentials * @param appsecret key * @return */ public static WeixinOauth2Token getToken(String appid, String appsecret, HttpServletRequest request) { WeixinOauth2Token wat = null; String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; requestUrl = requestUrl.replace("APPID", appid); requestUrl = requestUrl.replace("SECRET", appsecret); requestUrl = requestUrl.replace("CODE", request.getParameter("code")); //Initiate a GET request to get the credentials JSONObject jsonObject = httpsRequest(requestUrl, "GET", null); if (null != jsonObject) { try { what = new WeixinOauth2Token (); wat.setAccessToken(jsonObject.getString("access_token")); wat.setExpiresIn(jsonObject.getInt("expires_in")); wat.setRefreshToken(jsonObject.getString("refresh_token")); wat.setOpenId(jsonObject.getString("openid")); wat.setScope(jsonObject.getString("scope")); } catch (JSONException e) { what = null; // Failed to get token log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); } } return wat; } /** * URL encoding (utf-8) * * @param source * @return */ public static String urlEncodeUTF8(String source) { String result = source; try { result = java.net.URLEncoder.encode(source, "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace (); } return result; } /** * Determine file extension based on content type * * @param contentType content type * @return */ public static String getFileExt(String contentType) { String fileExt = ""; if ("image/jpeg".equals(contentType)) fileExt = ".jpg"; else if ("audio/mpeg".equals(contentType)) fileExt = ".mp3"; else if ("audio/amr".equals(contentType)) fileExt = ".amr"; else if ("video/mp4".equals(contentType)) fileExt = ".mp4"; else if ("video/mpeg4".equals(contentType)) fileExt = ".mp4"; return fileExt; } }
Then make an interceptor when accessing
package com.wonder.interceptor; import com.wonder.Util.CommonUtil; import com.wonder.entity.WeixinOauth2Token; import com.wonder.entity.WeixinUserInfo; import com.wonder.threadLocal.UserIdThreadLocal; import org.springframework.util.StringUtils; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; /** * Created by Guozhijie on 2016/10/27. */ public class WechatInterceptor implements HandlerInterceptor { public boolean preHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object handler) throws Exception{ String uri=httpServletRequest.getRequestURI(); WeixinUserInfo user=(WeixinUserInfo) httpServletRequest.getSession().getAttribute("user"); if(user!=null){ UserIdThreadLocal.setOpenId(Long.parseLong(user.getOpenId())); return true; } else{ try{ String code=httpServletRequest.getParameter("code"); if(StringUtils.isEmpty(code)){ httpServletResponse.sendRedirect(getUrl(httpServletRequest)); return false; } else{ String appid="wxd1f88b3343475e07"; String appSecret="*************"; WeixinOauth2Token token= CommonUtil.getToken(appid,appSecret,httpServletRequest); UserIdThreadLocal.setOpenId( Long.parseLong(token.getOpenId())); WeixinUserInfo weixinUserInfo=new WeixinUserInfo(); weixinUserInfo.setOpenId(token.getOpenId()); httpServletRequest.getSession().setAttribute("user",weixinUserInfo); return true; } }catch (Exception e){ e.printStackTrace (); httpServletResponse.sendRedirect(getUrl(httpServletRequest)); return false; } } } @Override public void postHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, org.springframework.web.servlet.ModelAndView modelAndView) throws Exception{} @Override public void afterCompletion(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception{} public String getUrl(HttpServletRequest request)throws UnsupportedEncodingException{ String requestUrl=request.getRequestURL().toString(); String redirectUri= URLEncoder.encode(requestUrl,"utf-8"); String appid="wxd1f88b3343475e07"; String url="https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appid+"&redirect_uri="+redirectUri+"&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect"; return url; } }
The function of interception is when the authorization is passed, if the user is the first time, the login method is used, and then the access_token and openid, unionid and unionid are obtained through appId, secret, code and stored in the database.
If you already have this user in the session, access it directly
If the access has no code parameter and no authorization, go to geturl to get the code and go to the authorization page
At this point, a question is what is the access situation when you are authorized and access this url for the second time,
In fact, if your Session has expired when you visit for the second time, you can still visit because it is based on your unionid on the WeChat server.
To judge whether you have authorized and then give you a code. At this time, because of the code parameter, I got the openId and went to the database to query and found that this user can be accessed directly.
It should be noted that scope permissions are divided into two types
Application authorization scope, snsapi_base (do not pop up the authorization page, jump directly, only get the user's openid), snsapi_userinfo (pop up the authorization page, you can get the nickname, gender, location through openid. And, even if you don't pay attention, As long as the user authorizes, the information can also be obtained )