一.先仔細研究一下微信掃碼登錄官方文檔
流程圖:
二.大致流程:
1. 開發者調用微信接口用於獲取掃描二維碼。
- 調用接口:
- 參數介紹:
2. 用戶掃描二維碼后該接口會自動返回重定向的資源上,並且帶上code和state參數,如果用戶拒絕授權只會帶上state參數
3. 開發者通過用微信另一個接口根據code和 appid,secret獲取access_token(也就是調用接口的憑證,有了他可以獲取里面的openid等信息)
- 調用接口:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
- 參數介紹
appid: 微信申請已存在的服務號的應用號;
secret:微信申請已存在的應用密匙;
code:調用上面一個接口自動返回的臨時票據。
grant_type:寫authorization_code
- 返回參數介紹
示例:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
access_token:接口調用憑證
expires_in:access_token接口調用憑證超時時間,單位(秒)
refresh_token: 用戶刷新access_token
openid:授權用戶唯一標識(常用)
scope:用戶授權的作用域
4.調用接口根據access_token和openid獲取個人用戶信息
- 調用接口:
http請求方式: GET
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
access_token:上個接口調用后返回的調用憑證
openid:上個接口獲取的授權用戶唯一標識
- 返回參數介紹
示例;
{
"openid":"OPENID",
"nickname":"NICKNAME",
"sex":1,
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"privilege":["PRIVILEGE1","PRIVILEGE2"],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
openid:授權用戶唯一標識
nickname:普通用戶昵稱
sex:普通用戶性別,1為男性,2為女性
province:普通用戶個人資料填寫的省份
city:普通用戶個人資料填寫的城市
country:國家,如中國為CN
headimgurl:用戶頭像,最后一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),用戶沒有頭像時該項為空
privilege:用戶特權信息,json數組,如微信沃卡用戶為(chinaunicom)
unionid:用戶統一標識。針對一個微信開放平台帳號下的應用,同一用戶的unionid是唯一的。
三.代碼實現:
1.創建相關工具類
- 封裝的幾個基礎類
a. access_token封裝基礎類
public class Token { private String openid; //授權用戶唯一標識 private String accessToken; //接口調用憑證 private Integer ExpiresIn; //access_token接口調用憑證超時時間,單位(秒) public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public String getAccessToken() { return accessToken; } public void setAccessToken(String accessToken) { this.accessToken = accessToken; } public Integer getExpiresIn() { return ExpiresIn; } public void setExpiresIn(Integer expiresIn) { ExpiresIn = expiresIn; }
b. 根據openid獲取用戶信息封裝成基礎類
public class WechatUserInfo { private String unionid; //用戶唯一標識
private String nickname; //昵稱
private String headimgurl; //頭像地址
private String subscribe; // 用戶是否訂閱該公眾號標識,值為0時,代表此用戶沒有關注該公眾號,拉取不到其余信息。 1 用戶已經綁定公眾號
public String getUnionid() { return unionid; } public void setUnionid(String unionid) { this.unionid = unionid; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public String getHeadimgurl() { return headimgurl; } public void setHeadimgurl(String headimgurl) { this.headimgurl = headimgurl; } public String getSubscribe() { return subscribe; } public void setSubscribe(String subscribe) { this.subscribe = subscribe; }
- 工具類
a. urlEncodeUTF8工具類(用於將掃描二維碼后重定向的資源url進行編碼)
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;
}
b. httpsRequest工具類(用於處理微信的獲取openid和用戶信息的接口的請求調用,返回相應的數據)
/**
* 發送https請求
* @param requestUrl 請求地址
* @param requestMethod 請求方式(GET、POST)
* @param outputStr 提交的數據
* @return 返回微信服務器響應的信息
*/
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) { try { // 創建SSLContext對象,並使用我們指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 從上述SSLContext對象中得到SSLSocketFactory對象
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); // 設置請求方式(GET/POST)
conn.setRequestMethod(requestMethod); conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); // 當outputStr不為null時向輸出流寫數據
if (null != outputStr) { OutputStream outputStream = conn.getOutputStream(); // 注意編碼格式
outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 從輸入流讀取返回內容
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); } // 釋放資源
bufferedReader.close(); inputStreamReader.close(); inputStream.close(); inputStream = null; conn.disconnect(); return buffer.toString(); } catch (ConnectException ce) { log.error("連接超時:{}", ce); } catch (Exception e) { log.error("https請求異常:{}", e); } return null; }
c. 獲取openid等信息的方法
public static Token getTokenWithOpenid(String appid, String appsecret, String code) { String findAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; Token token = null; String requestUrl = findAccessTokenUrl.replace("APPID", appid).replace("SECRET", appsecret).replace("CODE", code);// 發起GET請求獲取憑證
JSONObject jsonObject = JSONObject.fromObject(httpsRequest(requestUrl, "GET", null)); if (null != jsonObject) { try { token = new Token();
token.setOpenid(jsonObject.getString("openid")); token.setAccessToken(jsonObject.getString("access_token")); token.setExpiresIn(jsonObject.getInt("expires_in")); } catch (JSONException e) { token = null; // 獲取token失敗
log.error("獲取token失敗 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); } } return token; }
d. 根據openid獲取用戶信息的方法
public static WechatUserInfo getUserinfo(String access_token, String openid) { WechatUserInfo wxuse = new WechatUserInfo();
String findUseinfo = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID"; String requestUrl = findUseinfo.replace("ACCESS_TOKEN", access_token).replace("OPENID", openid); JSONObject jsonObject = JSONObject.fromObject(httpsRequest(requestUrl, "GET", null)); if (null != jsonObject) { try { wxuse.setNickname(jsonObject.getString("nickname")); wxuse.setHeadimgurl(jsonObject.getString("headimgurl")); wxuse.setUnionid(jsonObject.getString("unionid")); } catch (JSONException e) { e.printStackTrace(); } } return wxuse; }
- 操作:
a. 跳轉至登錄授權頁面(頁面出現二維碼)
public String weChatLanded(){ String requestUrl = "https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect"; String loginAppid = "wxea43f181e32e8df0"; //微信申請的appid
String loginRedirectUrl = "https://www.homepin.cn/weChatLogin_epf.action";//調用微信接口后返回的資源名
String loginScope = "snsapi_login";//寫死
redirectURL = requestUrl.replace("APPID", loginAppid).replace("REDIRECT_URI", CommonUtil.urlEncodeUTF8(loginRedirectUrl)).replace("SCOPE", loginScope); return SUCCESS; }
b. 授權成功后:
@SuppressWarnings("static-access") public String weChatLogin_epf(){ //通過code獲取access_token
String loginAppid = "wxea43f181e32e8df0"; String loginSecrect = "4721e5f744e6c0f3c4094b25449ee7e3"; Token tokenWithOpenid = CommonUtil.getTokenWithOpenid(loginAppid, loginSecrect,code); String openid = tokenWithOpenid.getOpenid(); String access_token = tokenWithOpenid.getAccessToken(); //通過access_token調用接口
WechatUserInfo wxuse = CommonUtil.getUserinfo(access_token, openid); return SUCCESS; }