java實(shí)現(xiàn)微信掃碼登錄第三方網(wǎng)站功能(原理和代碼)
為避免繁瑣的注冊登陸,很多平臺和網(wǎng)站都會實(shí)現(xiàn)三方登陸的功能,增強(qiáng)用戶的粘性。這篇文章主要介紹了java實(shí)現(xiàn)微信掃碼登錄第三方網(wǎng)站功能(原理和代碼),避免做微信登錄開發(fā)的朋友們少走彎路。
一.查看微信掃碼登錄官方文檔
1.在進(jìn)行第三方授權(quán)登錄之前,需要在微信開放平臺注冊開發(fā)者賬號,拿到相應(yīng)的AppId和AppSecret以及redirect_uri,即可進(jìn)行授權(quán)接入流程;
2.第三方可以獲取到用戶的接口調(diào)用憑證(access_token),通過access_token可以進(jìn)行微信開放平臺授權(quán)關(guān)系接口調(diào)用,從而可實(shí)現(xiàn)獲取微信用戶基本開放信息和幫助用戶實(shí)現(xiàn)基礎(chǔ)開放功能等。
獲取access_token時(shí)序圖:
二.實(shí)現(xiàn)微信第三方登錄流程:
1. 開發(fā)者調(diào)用微信接口用于獲取掃描二維碼。
調(diào)用接口:
參數(shù)介紹:
appid: 微信申請已存在的服務(wù)號的應(yīng)用號;
redirect_uri: 回調(diào)地址,掃完碼之后微信會將code這個(gè)值傳到這個(gè)地址上,注意:回調(diào)地址需要用urlEncode處理;
responseType: 填code;
scope: 網(wǎng)頁應(yīng)用僅填snsapi_login;
state: 用于保持請求和回調(diào)的狀態(tài),授權(quán)請求后原樣帶給第三方,可用于防止跨站攻擊;
2. 用戶掃描二維碼后該接口會自動(dòng)返回重定向的資源上,并且?guī)蟘ode和state參數(shù),如果用戶拒絕授權(quán)只會帶上state參數(shù)
3. 開發(fā)者通過用微信另一個(gè)接口根據(jù)code和 appid,secret獲取access_token(也就是調(diào)用接口的憑證,有了他可以獲取里面的openid等信息)
調(diào)用接口:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
- 參數(shù)介紹
appid: 微信申請已存在的服務(wù)號的應(yīng)用號;
secret:微信申請已存在的應(yīng)用密匙;
code:調(diào)用上面一個(gè)接口自動(dòng)返回的臨時(shí)票據(jù)。
grant_type:寫authorization_code
返回參數(shù)介紹
示例: { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
access_token:接口調(diào)用憑證
expires_in:access_token接口調(diào)用憑證超時(shí)時(shí)間,單位(秒)
refresh_token: 用戶刷新access_token
openid:授權(quán)用戶唯一標(biāo)識(常用)
scope:用戶授權(quán)的作用域
4.調(diào)用接口根據(jù)access_token和openid獲取個(gè)人用戶信息
調(diào)用接口:
http請求方式: GET
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
access_token:上個(gè)接口調(diào)用后返回的調(diào)用憑證
openid:上個(gè)接口獲取的授權(quán)用戶唯一標(biāo)識返回參數(shù)介紹
示例; { "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:授權(quán)用戶唯一標(biāo)識
nickname:普通用戶昵稱
sex:普通用戶性別,1為男性,2為女性
province:普通用戶個(gè)人資料填寫的省份
city:普通用戶個(gè)人資料填寫的城市
country:國家,如中國為CN
headimgurl:用戶頭像,最后一個(gè)數(shù)值代表正方形頭像大?。ㄓ?、46、64、96、132數(shù)值可選,0代表640*640正方形頭像),用戶沒有頭像時(shí)該項(xiàng)為空
privilege:用戶特權(quán)信息,json數(shù)組,如微信沃卡用戶為(chinaunicom)
unionid:用戶統(tǒng)一標(biāo)識。針對一個(gè)微信開放平臺帳號下的應(yīng)用,同一用戶的unionid是唯一的。
三.代碼實(shí)現(xiàn):
1.創(chuàng)建相關(guān)工具類
封裝的幾個(gè)基礎(chǔ)類
a. access_token封裝基礎(chǔ)類
public class Token { private String openid; //授權(quán)用戶唯一標(biāo)識 private String accessToken; //接口調(diào)用憑證 private Integer ExpiresIn; //access_token接口調(diào)用憑證超時(shí)時(shí)間,單位(秒) 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. 根據(jù)openid獲取用戶信息封裝成基礎(chǔ)類
public class WechatUserInfo { private String unionid; //用戶唯一標(biāo)識 private String nickname; //昵稱 private String headimgurl; //頭像地址 private String subscribe; // 用戶是否訂閱該公眾號標(biāo)識,值為0時(shí),代表此用戶沒有關(guān)注該公眾號,拉取不到其余信息。 1 用戶已經(jīng)綁定公眾號 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進(jìn)行編碼)
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和用戶信息的接口的請求調(diào)用,返回相應(yīng)的數(shù)據(jù))
/** * 發(fā)送https請求 * @param requestUrl 請求地址 * @param requestMethod 請求方式(GET、POST) * @param outputStr 提交的數(shù)據(jù) * @return 返回微信服務(wù)器響應(yīng)的信息 */ public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) { try { // 創(chuàng)建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); // 設(shè)置請求方式(GET/POST) conn.setRequestMethod(requestMethod); conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); // 當(dāng)outputStr不為null時(shí)向輸出流寫數(shù)據(jù) if (null != outputStr) { OutputStream outputStream = conn.getOutputStream(); // 注意編碼格式 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 從輸入流讀取返回內(nèi)容 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("連接超時(shí):{}", 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);// 發(fā)起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. 根據(jù)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. 跳轉(zhuǎn)至登錄授權(quán)頁面(頁面出現(xiàn)二維碼)
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 = "http://www.dbjr.com.cn/weChatLogin_epf.action";//調(diào)用微信接口后返回的資源名 String loginScope = "snsapi_login";//寫死 redirectURL = requestUrl.replace("APPID", loginAppid).replace("REDIRECT_URI", CommonUtil.urlEncodeUTF8(loginRedirectUrl)).replace("SCOPE", loginScope); return SUCCESS; }
b. 授權(quán)成功后:
@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調(diào)用接口 WechatUserInfo wxuse = CommonUtil.getUserinfo(access_token, openid); return SUCCESS; }
到此這篇關(guān)于java實(shí)現(xiàn)微信掃碼登錄第三方網(wǎng)站功能(原理和代碼)的文章就介紹到這了,更多相關(guān)java微信第三方登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java后端接入微信小程序登錄功能(登錄流程)
- 微信小程序微信登錄的實(shí)現(xiàn)方法詳解(JAVA后臺)
- 詳解java實(shí)現(xiàn)簡單掃碼登錄功能(模仿微信網(wǎng)頁版掃碼)
- Java中基于Shiro,JWT實(shí)現(xiàn)微信小程序登錄完整例子及實(shí)現(xiàn)過程
- 使用weixin-java-tools完成微信授權(quán)登錄、微信支付的示例
- java實(shí)現(xiàn)微信小程序登錄態(tài)維護(hù)的示例代碼
- 第三方網(wǎng)站微信登錄java代碼實(shí)現(xiàn)
- java實(shí)現(xiàn) 微博登錄、微信登錄、qq登錄實(shí)現(xiàn)代碼
- Java實(shí)現(xiàn)微信登錄并獲取用戶信息功能(開發(fā)流程)
相關(guān)文章
SpringBoot結(jié)合FreeMarker視圖渲染的實(shí)現(xiàn)
FreeMarker它允許開發(fā)人員使用模板和數(shù)據(jù)來生成輸出文本,如HTML網(wǎng)頁、電子郵件、配置文件和源代碼等,本文主要介紹了SpringBoot結(jié)合FreeMarker視圖渲染的實(shí)現(xiàn),感興趣的可以了解一下2024-03-03SpringBoot優(yōu)化連接數(shù)的方法詳解
SpringBoot開發(fā)最大的好處是簡化配置,內(nèi)置了Tomcat,下面這篇文章主要給大家介紹了關(guān)于SpringBoot優(yōu)化連接數(shù)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06application.yml和bootstrap.yml不生效的3種解決方案
SpringBoot默認(rèn)支持?properties(.properties) 和 YAML(.yml .yaml ) 配置文件,本文主要介紹了application.yml和bootstrap.yml不生效的3種解決方案,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03Java?KeyGenerator.generateKey的19個(gè)方法代碼示例
在下文中一共展示了KeyGenerator.generateKey方法的19個(gè)代碼示例,這些例子默認(rèn)根據(jù)受歡迎程度排序2021-12-12詳解Java中LinkedStack鏈棧的實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Java中LinkedStack鏈棧的相關(guān)知識,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Java有一定幫助,需要的可以參考一下2022-11-11