恢復內容開始 1.背景:現在很多app或者網站都想要接入微信登錄,可以使用戶不需要註冊就能快速使用APP或網站。 2.微信登錄需要一些前置操作 2.1 搜索:微信開放平臺 鏈接:https://open.weixin.qq.com/ 2.2 註冊成功,獲取到開發所需要的appID和appsecret ...
------------恢復內容開始------------
1.背景:現在很多app或者網站都想要接入微信登錄,可以使用戶不需要註冊就能快速使用APP或網站。
2.微信登錄需要一些前置操作
2.1 搜索:微信開放平臺 鏈接:https://open.weixin.qq.com/
2.2 註冊成功,獲取到開發所需要的appID和appsecret
3.微信的登錄的交互流程
3.1 微信用戶首先向第三APP請求登錄
3.2 第三APP彈出一個二維碼(這個二維碼可以由客戶端或者H5去做),用戶掃描二維(請求微信Oauth2.0授權登錄)
3.3 app彈出一個確認登錄的頁面(微信平臺請求用戶確認)
3.4 用戶點擊確認
3.5 微信公眾平臺拉起第三方或者重定向到第三方,帶上授權臨時票據code(前端或者客戶端的工作,前端把回調地址放在3.2步驟的,或者在公眾平臺配置)
3.6 請求到服務端:服務端需要把code、appId、appscret作為參數,在程式內部調起微信介面,獲取到access_token和openId
3.7 獲取到用戶的access_token和openId後就可以獲取到用戶的微信信息了
3.8 獲取到用戶unionId後,後端進行存儲,為該用戶生成一條用戶信息,用戶登錄成功,後端可以重定向到前端某一個登錄的頁面,也可以讓前端,根據返回值進行跳 轉
3.9 登錄成功後的操作,前端請求後端介面時把unionId帶上,後端根據unionId,確定,當前用戶unionId,找到用戶在自己APP的ID
4. 附上完整代碼:
HTTPClient:maven 依賴
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.3.6</version>
</dependency>
1 package com.example.student.project.controller; 2 3 import com.example.student.project.domain.WXUserInfoData; 4 import org.apache.commons.lang3.StringUtils; 5 import org.apache.http.HttpEntity; 6 import org.apache.http.HttpResponse; 7 import org.apache.http.client.ClientProtocolException; 8 import org.apache.http.client.methods.HttpGet; 9 import org.apache.http.client.methods.HttpUriRequest; 10 import org.apache.http.entity.ContentType; 11 import org.apache.http.impl.client.CloseableHttpClient; 12 import org.apache.http.impl.client.HttpClientBuilder; 13 import org.apache.http.util.EntityUtils; 14 import org.slf4j.Logger; 15 import org.slf4j.LoggerFactory; 16 import org.springframework.boot.configurationprocessor.json.JSONException; 17 import org.springframework.boot.configurationprocessor.json.JSONObject; 18 import org.springframework.stereotype.Controller; 19 import org.springframework.web.bind.annotation.RequestMapping; 20 import org.springframework.web.bind.annotation.RequestMethod; 21 import org.springframework.web.bind.annotation.ResponseBody; 22 23 import java.io.IOException; 24 import java.io.UnsupportedEncodingException; 25 import java.net.URLEncoder; 26 import java.nio.charset.Charset; 27 import java.nio.charset.StandardCharsets; 28 import java.util.Map; 29 30 @Controller 31 @RequestMapping(value = "/CourtSystem") 32 public class WeiXinLoginController { 33 34 private static final Logger logger = LoggerFactory.getLogger(WeiXinLoginController.class); 35 36 public static final String WX_AUTH_LOGIN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token"; 37 public static final String WX_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo"; 38 //appid和appSecret 是在公眾平臺上申請的 39 //AppId:應用唯一標識,在微信開放平臺提交應用審核通過後獲得 40 public static final String WX_APP_ID = "wx9ecd6f7******"; 41 //AppSecret:應用密鑰AppSecret,在微信開放平臺提交應用審核通過後獲得 42 public static final String WX_APP_KEY = "c1bf387181aaf6e5ff********"; 43 44 45 /** 46 * 第三方微信登錄 47 * @param code 客戶端返回的code 48 * @return 49 */ 50 @RequestMapping(value = "/checkLogin", method = RequestMethod.POST) 51 @ResponseBody 52 public WXUserInfoData checkLogin(String code) throws JSONException { 53 //通過code獲取access_token 54 //String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code" 55 StringBuffer loginUrl = new StringBuffer(); 56 //url拼接 57 // WX_AUTH_LOGIN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token" 58 //AppId:應用唯一標識,在微信開放平臺提交應用審核通過後獲得 59 //WX_APP_ID = "wx9ecd6f7******"; 60 //AppSecret:應用密鑰AppSecret,在微信開放平臺提交應用審核通過後獲得 61 //WX_APP_KEY = "c1bf387181aaf6e5ff********"; 62 loginUrl.append(WX_AUTH_LOGIN_URL).append("?appid=") //AppId 63 .append(WX_APP_ID).append("&secret=") //AppSecret 64 .append(WX_APP_KEY).append("&code=").append(code) //填寫第二步獲取的code參數 65 .append("&grant_type=authorization_code"); //填authorization_code(固定,來自於官方文檔) 66 String loginRet = get(loginUrl.toString()); 67 JSONObject grantObj = new JSONObject(loginRet); 68 String errcode = grantObj.optString("errcode"); 69 if (!StringUtils.isEmpty(errcode)) 70 { 71 logger.error("login weixin error"+loginRet); 72 return null; 73 } 74 String openId = grantObj.optString("openid"); 75 if (StringUtils.isEmpty(openId)) 76 { 77 logger.error("login weixin getOpenId error"+loginRet); 78 return null; 79 } 80 81 String accessToken = grantObj.optString("access_token"); //介面調用憑證 82 String expiresIn = grantObj.optString("expires_in"); // access_token介面調用憑證超時時間,單位(秒) 83 String refreshToken = grantObj.optString("refresh_token"); //用戶刷新access_token 84 String scope = grantObj.optString("scope"); //用戶授權的作用域,使用逗號(,)分隔 85 86 //通過access_token獲取用戶微信信息 87 StringBuffer userUrl = new StringBuffer(); 88 // String url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID"; 89 // 第三步獲取的access_token ; OPENID:第三步獲取的openId 90 //WX_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo" 91 userUrl.append(WX_USERINFO_URL).append("?access_token=").append(accessToken).append("&openid=").append(openId); 92 String userRet = get(userUrl.toString()); 93 JSONObject userObj = new JSONObject(userRet); 94 WXUserInfoData userInfo = new WXUserInfoData(); 95 userInfo.setOpenId(openId); // 用戶標識 96 userInfo.setAuthToken(accessToken); 97 userInfo.setAuthRefreshToken(refreshToken); // 專用於刷新access token的token 98 userInfo.setScope(scope); // scope:許可權 99 userInfo.setExpiresIn(Integer.valueOf(expiresIn)); 100 String nickname = userObj.optString("nickname"); // 用戶昵稱 101 String sex = userObj.optString("sex"); // 1男,2女,0未知 102 String userImg = userObj.optString("headimgurl"); //頭像鏈接 103 String unionid = userObj.optString("unionid"); //全局唯一標識 104 userInfo.setName(nickname); 105 userInfo.setIcon(userImg); 106 userInfo.setGender(sex); 107 userInfo.setLoginId(unionid); 108 return userInfo; 109 } 110 111 112 public static String get(String url) { 113 String body = null; 114 try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { 115 logger.info("create httppost:" + url); 116 HttpGet get = new HttpGet(url); 117 get.addHeader("Accept-Charset","utf-8"); 118 HttpResponse response = sendRequest(httpClient, get); 119 body = parseResponse(response); 120 } catch (IOException e) { 121 logger.error("send post request failed: {}", e.getMessage()); 122 } 123 124 return body; 125 } 126 127 private static String paramsToString(Map<String, String> params) { 128 StringBuilder sb = new StringBuilder(); 129 try{ 130 for (String key : params.keySet()) { 131 sb.append(String.format("&%s=%s", key, URLEncoder.encode(params.get(key), StandardCharsets.UTF_8.toString()))); 132 } 133 }catch(UnsupportedEncodingException e){ 134 logger.warn("{}: encode url parameters failed", e.getMessage()); 135 } 136 return sb.length() > 0 ? "?".concat(sb.substring(1)) : ""; 137 } 138 139 private static HttpResponse sendRequest(CloseableHttpClient httpclient, HttpUriRequest httpost) 140 throws ClientProtocolException, IOException { 141 HttpResponse response = null; 142 response = httpclient.execute(httpost); 143 return response; 144 } 145 146 private static String parseResponse(HttpResponse response) { 147 logger.info("get response from http server.."); 148 HttpEntity entity = response.getEntity(); 149 150 logger.info("response status: " + response.getStatusLine()); 151 Charset charset = ContentType.getOrDefault(entity).getCharset(); 152 if (charset != null) { 153 logger.info(charset.name()); 154 } 155 156 String body = null; 157 try { 158 body = EntityUtils.toString(entity, "utf-8"); 159 logger.info("body " + body); 160 } catch (IOException e) { 161 logger.warn("{}: cannot parse the entity", e.getMessage()); 162 } 163 164 return body; 165 } 166 167 168 }View Code