一、準備工作
注冊微信開放平臺的賬號,創(chuàng)建網(wǎng)站應用,準備妥當之后,我們需要的是AppID和AppSecret。
二、解讀官方文檔
獲取access_token時序圖:

時序圖解讀
- 用戶點擊微信登錄的按鈕
- 三方應用攜帶AppID請求微信OAuth2.0授權登錄
- 用戶微信授權后
- 微信返回臨時參數(shù)code重定向到后端接口
- 后端接口攜帶code、App ID和AppSecret請求access_token
- 微信返回access_token
時序圖總結:由此可見,我們在進行掃碼登錄時獲取的只是臨時授權碼code,需要攜帶code、App ID和AppSecret一同獲取access_token,access_token才是我們后期調用微信接口的真正憑證。
三、獲取code
請求鏈接
參數(shù)說明
appid:應用唯一標識,必須
redirect_uri:回調url,與創(chuàng)建應用時所填url一致,需要用urlEncode處理,必須
response_type:固定填code,必須
scope:網(wǎng)站應用目前僅填snsapi_login,必須
state:用于保持請求和回調的狀態(tài),選填(微信開放平臺建議攜帶)
Java代碼實現(xiàn)
public class WxLoginController {
private static String APP_ID = "AppID";
private static String Code_Url = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_login&state=STATE#wechat_redirect";
// 回調url,與網(wǎng)站應用一致
private static String Redirect_Url = "http://xxx.com";
@SneakyThrows
@RequestMapping("/getCode")
public void getCode(HttpServletResponse response) {
// 按照微信要求處理回調url
String redirect_url = URLEncoder.encode(Redirect_Url, StandardCharsets.UTF_8);
// 拼裝url
String url = String.format(Code_Url, APP_ID, redirect_url);
log.info(url);
response.sendRedirect(url);
}
}
運行結果圖

掃碼登錄后就會發(fā)現(xiàn)攜帶code回調成功

還有一種更加美觀化的獲取code的方式,內嵌二維碼,和上面的步驟一樣,這里就直接貼出官方文檔和實現(xiàn)代碼

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
</head>
<body>
<!-- 放置二維碼的div -->
<div id="login_container"></div>
</body>
<script type="text/javascript">
var obj = new WxLogin({
self_redirect:true,
id:"login_container",
appid: "AppID",
scope: "snsapi_login",
redirect_uri: encodeURI("http://xxx.com/"),
state: "STATE"
});
</script>
</html>
四、獲取access_token
前面我們提到,獲取code的目的只是為了得到access_token。
請求鏈接
參數(shù)說明
appid:應用唯一標識,必須
secret:應用密鑰AppSecret,必須
code:填寫之前獲取的code參數(shù),必須
grant_type:填authorization_code,必須
Java代碼實現(xiàn)
public class WxLoginController {
private static String APP_ID = "AppID";
private static String APP_SECRET = "AppSecret";
private static String Access_Toke_Url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
private static String UserInfo_Url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
private static String Code_Url = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_login&state=STATE#wechat_redirect";
// 回調url,與網(wǎng)站應用一致
private static String Redirect_Url = "http://xxx.com";
@SneakyThrows
@RequestMapping("/getCode")
public void getCode(HttpServletResponse response) {
// 按照微信要求處理回調url
String redirect_url = URLEncoder.encode(Redirect_Url, StandardCharsets.UTF_8);
// 拼裝url
String url = String.format(Code_Url, APP_ID, redirect_url);
log.info(url);
response.sendRedirect(url);
}
@GetMapping("/getAccessToken")
public String getAccessToken(String code) throws IOException {
// 拼裝url
String url = String.format(Access_Toke_Url, APP_ID, APP_SECRET, code);
log.info("獲取access_token的url: " + url);
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
// 發(fā)送get請求獲取access_token
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity);
log.info("響應數(shù)據(jù): " + content);
httpClient.close();
return content;
}
}
成功獲取access_token

返回參數(shù)說明
access_token:接口調用憑證
expires_in:access_token接口調用憑證超時時間,單位(秒)
refresh_token:用戶刷新access_token
openid:授權用戶唯一標識
scope:用戶授權的作用域,使用逗號(,)分隔
unionid:當且僅當該網(wǎng)站應用已獲得該用戶的userinfo授權時,才會出現(xiàn)該字段