微信網(wǎng)站掃一掃登錄
個(gè)人blog+bbs www.youngboy.vip
上手須知
要想使用微信掃一掃就可以登錄網(wǎng)站,首先要有微信開(kāi)發(fā)平臺(tái)賬號(hào)址貌,并且通過(guò)開(kāi)發(fā)者資質(zhì)認(rèn)證(認(rèn)證需要通過(guò)審核练对,審核費(fèi)300人民幣),然后添加網(wǎng)頁(yè)應(yīng)用準(zhǔn)備網(wǎng)站信息登記表等信息提價(jià)審核虚青,有公眾號(hào)的可以綁定公眾號(hào)棒厘,最終你會(huì)得到 appid 和 appsecret 然后就可以愉快的玩耍了
科普微信授權(quán)原理
微信用戶(hù)->第三方應(yīng)用: 請(qǐng)求登錄第三方應(yīng)用
第三方應(yīng)用->微信開(kāi)發(fā)平臺(tái): 請(qǐng)求oauth2授權(quán)
微信開(kāi)發(fā)平臺(tái)->微信用戶(hù): 請(qǐng)求用戶(hù)確認(rèn)
微信用戶(hù)->微信開(kāi)發(fā)平臺(tái): 用戶(hù)確認(rèn)
微信開(kāi)發(fā)平臺(tái)-> 第三方應(yīng)用: 拉起第三方應(yīng)用或重定向到第三方的服務(wù)器奢人,并帶上code
第三方應(yīng)用 -> 微信開(kāi)發(fā)平臺(tái): 通過(guò)code加上appid appsecret獲取access_token
微信開(kāi)發(fā)平臺(tái) -> 第三方應(yīng)用: 返回用戶(hù)相關(guān)信息
前端的打開(kāi)方式
前端有兩種打開(kāi)方式
- 通過(guò)重定向到微信的頁(yè)面然后用戶(hù)掃描二維碼授權(quán)淆院,再重定向回第三方網(wǎng)站
- 通過(guò)js直接顯示二維碼登錄土辩,不用跳轉(zhuǎn)微信頁(yè)面
第一種方式是通過(guò)后臺(tái)重定向過(guò)去的所以前端只需要寫(xiě)個(gè)鏈接就行了宪赶,第二種方式是在頁(yè)面上直接顯示二維碼登錄減少了跳頁(yè)面的時(shí)間,這種方式需要在網(wǎng)頁(yè)上用js實(shí)現(xiàn)脯燃,一般第二種用的比較多
使用js顯示微信掃一掃二維碼的打開(kāi)方式
步驟1
:在頁(yè)面中先引入如下JS文件(支持https):
https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
步驟2
:在需要使用微信登錄的地方實(shí)例以下JS對(duì)象:
var obj = new WxLogin({
id:"login_container", // 需要顯示的容器id
appid: "", // 公眾號(hào)appid wx*******
scope: "snsapi_login", // 網(wǎng)頁(yè)默認(rèn)即可
redirect_uri: "", // 授權(quán)成功后回調(diào)的url
state: "", // 可設(shè)置為簡(jiǎn)單的隨機(jī)數(shù)加session用來(lái)校驗(yàn)
style: "black", // 提供"black"、"white"可選蒙保。二維碼的樣式
href: "" // 外部css文件url辕棚,需要https
});
參數(shù)說(shuō)明
參數(shù) | 是否必須 | 說(shuō)明 |
---|---|---|
self_redirect | 否 | true:手機(jī)點(diǎn)擊確認(rèn)登錄后可以在 iframe 內(nèi)跳轉(zhuǎn)到 redirect_uri,false:手機(jī)點(diǎn)擊確認(rèn)登錄后可以在 top window 跳轉(zhuǎn)到 redirect_uri邓厕。默認(rèn)為 false逝嚎。 |
id | 是 | 第三方頁(yè)面顯示二維碼的容器id |
appid | 是 | 應(yīng)用唯一標(biāo)識(shí),在微信開(kāi)放平臺(tái)提交應(yīng)用審核通過(guò)后獲得 |
scope | 是 | 應(yīng)用授權(quán)作用域补君,擁有多個(gè)作用域用逗號(hào)(,)分隔,網(wǎng)頁(yè)應(yīng)用目前僅填寫(xiě)snsapi_login即可 |
redirect_uri | 是 | 重定向地址昧互,需要進(jìn)行UrlEncode |
state | 否 | 用于保持請(qǐng)求和回調(diào)的狀態(tài)挽铁,授權(quán)請(qǐng)求后原樣帶回給第三方。該參數(shù)可用于防止csrf攻擊(跨站請(qǐng)求偽造攻擊)敞掘,建議第三方帶上該參數(shù)叽掘,可設(shè)置為簡(jiǎn)單的隨機(jī)數(shù)加session進(jìn)行校驗(yàn) |
style | 否 | 提供"black"、"white"可選玖雁,默認(rèn)為黑色文字描述 |
href | 否 | 自定義樣式鏈接更扁,第三方可根據(jù)實(shí)際需求覆蓋默認(rèn)樣式 |
用戶(hù)點(diǎn)擊確認(rèn)授權(quán)后網(wǎng)頁(yè)會(huì)自動(dòng)跳轉(zhuǎn)redirect_uri
前端掃碼分析
https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js 的代碼
!function(a, b, c) {
function d(a) {
var c = "default";
a.self_redirect === !0 ? c = "true": a.self_redirect === !1 && (c = "false");
var d = b.createElement("iframe"),
e = "https://open.weixin.qq.com/connect/qrconnect?appid=" + a.appid + "&scope=" + a.scope + "&redirect_uri=" + a.redirect_uri + "&state=" + a.state + "&login_type=jssdk&self_redirect=" + c;
e += a.style ? "&style=" + a.style: "",
e += a.href ? "&href=" + a.href: "",
d.src = e,
d.frameBorder = "0",
d.allowTransparency = "true",
d.scrolling = "no",
d.width = "300px",
d.height = "400px";
var f = b.getElementById(a.id);
f.innerHTML = "",
f.appendChild(d)
}
a.WxLogin = d
} (window, document);
上段代碼主要功能是根據(jù)用戶(hù)配置的消息在頁(yè)面上嵌入一個(gè)iframe,我們看到的二維碼是iframe和請(qǐng)掃描等提示語(yǔ)都是iframe中的
這里先給大家一個(gè)鏈接看看 點(diǎn)我
打開(kāi)iframe的鏈接返回的是一個(gè)網(wǎng)頁(yè),再打開(kāi)游覽器的開(kāi)發(fā)者工具可以看到一個(gè)長(zhǎng)連接請(qǐng)求
https://long.open.weixin.qq.com/connect/l/qrconnect?uuid=081ciRVWnFkIOwL8&_=1534297144336
這個(gè)請(qǐng)求帶有兩個(gè)參數(shù)一個(gè)是 uuid
還有一個(gè) 是 _
看樣子應(yīng)該是時(shí)間戳,這個(gè)請(qǐng)求在沒(méi)掃描之前一直是阻塞
的,如果27秒沒(méi)有掃碼會(huì)自動(dòng)斷開(kāi)連接浓镜,并且返回一段js代碼
window.wx_errcode=408;window.wx_code='';
再來(lái)看看網(wǎng)頁(yè)中嵌入的一段代碼,這里我省略了一些代碼只留下比較重要的
!function() {
function a(d) {
jQuery.ajax({
type: "GET",
url: "https://long.open.weixin.qq.com/connect/l/qrconnect?uuid=011ZJt4N2TyhElXu" + (d ? "&last=" + d: ""),
dataType: "script", //這里是script類(lèi)型
cache: !1,
timeout: 6e4,
success: function(d, e, f) {
var g = window.wx_errcode;//這里為什么是window.wx_errcode呢 因?yàn)榉祷氐母袷绞莝cript 內(nèi)容是 window.wx_errcode=408;window.wx_code='';
switch (g) {
case 405://如果是405證明用戶(hù)已經(jīng)同意授權(quán)登錄 用js重定向并帶上code
var h = "http://www.reibang.com/users/auth/wechat/callback";
h = h.replace(/&/g, "&"),
h += (h.indexOf("?") > -1 ? "&": "?") + "code=" + wx_code + "&state=123";
var i = b("self_redirect");
if (c) if ("true" !== i && "false" !== i) try {
document.domain = "qq.com";
var j = window.top.location.host.toLowerCase();
j && (window.location = h)
} catch(k) {
window.top.location = h
} else if ("true" === i) try {
window.location = h
} catch(k) {
window.top.location = h
} else window.top.location = h;
else window.location = h;
break;
case 404:
jQuery(".js_status").hide(),
jQuery("#wx_after_scan").show(),
setTimeout(a, 100, g);
break;
case 403:
jQuery(".js_status").hide(),
jQuery("#wx_after_cancel").show(),
setTimeout(a, 2e3, g);
break;
case 402:
case 500:
window.location.reload();
break;
case 408:
setTimeout(a, 2e3)
}
},
error: function(b, c, d) {
var e = window.wx_errcode;
408 == e ? setTimeout(a, 5e3) : setTimeout(a, 5e3, e)
}
})
}
...
} ();
上面的代碼是一段自執(zhí)行函數(shù)溃列,鏈接一打開(kāi)就會(huì)執(zhí)行,在用戶(hù)掃碼之前請(qǐng)求是阻塞的success回調(diào)都不會(huì)執(zhí)行膛薛,如果用戶(hù)一直沒(méi)有掃描二維碼听隐,請(qǐng)求在27秒內(nèi)就會(huì)斷開(kāi)鏈接這時(shí)就會(huì)去執(zhí)行success回調(diào)函數(shù)并且重新發(fā)起一個(gè)長(zhǎng)連接重復(fù)以上步驟直到返回405
網(wǎng)頁(yè)中的二維碼解析后的結(jié)果是
https://open.weixin.qq.com/connect/confirm?uuid=0618LnlRCFd-jYeo
這個(gè)鏈接只有一個(gè)參數(shù)并且uuid和長(zhǎng)連接請(qǐng)求的uuid是相同的,用游覽器打開(kāi)會(huì)提示Scope 參數(shù)錯(cuò)誤或沒(méi)有 Scope 權(quán)限相叁,只能用微信打開(kāi)才有用遵绰,微信的包不好抓希望有大神能夠指點(diǎn)指點(diǎn)
后端的打開(kāi)方式
重定向到微信頁(yè)面的打開(kāi)方式
登錄你的網(wǎng)站應(yīng)用
https://xxx.xxx.com/wechat/login.do
打開(kāi)后需要重定向至微信的地址并帶上必要的參數(shù)
https://open.weixin.qq.com/connect/qrconnect?
appid=wxbdc5610cc59c1631
&
redirect_uri=https%3A%2F%2Fxxx.xxx.com%2Fwechat%2Fcallback.do
&
response_type=code
&
scope=snsapi_login
&
state=3d6be0a4035d839573b04816624a415e#wechat_redirect
這里需要變的參數(shù)是appid和redirect_url
訪(fǎng)問(wèn)以上鏈接微信開(kāi)發(fā)平臺(tái)會(huì)重定向到redirect_uri的網(wǎng)址上,并且?guī)?code>code和state
參數(shù)增淹,如果用戶(hù)沒(méi)有授權(quán)就不會(huì)有code
參數(shù)椿访,僅會(huì)帶上state參數(shù)
https://xxx.xxx.com?code=xxx&state=xxx
后臺(tái)根據(jù)code獲取用戶(hù)信息封裝
獲取用戶(hù)信息的步驟
- 通過(guò)code獲取access_token
- 通過(guò)access_token調(diào)用接口
這里使用了weixin-java-tools
工具來(lái)獲取用戶(hù)信息
github地址 傳送門(mén)
public WxMpUser getWxUser(String code) {
if (code == null) {
return null;
}
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = null;
WxMpUser wxMpUser = null;
try {
wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
wxMpOAuth2AccessToken = wxMpService.oauth2refreshAccessToken(wxMpOAuth2AccessToken.getRefreshToken());
wxMpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, null);
} catch (WxErrorException e) {
return null;
}
return wxMpUser;
}
Java 長(zhǎng)連接模擬微信登錄
[圖片上傳失敗...(image-6193f9-1557819001579)]
實(shí)現(xiàn)原理
使用Servlet3異步接口實(shí)現(xiàn)非阻塞長(zhǎng)連接接口, 異步上下文對(duì)象使用 ScheduledExecutorService 線(xiàn)程池定時(shí)調(diào)度 事件總線(xiàn)使用了 guava 中的 EventBus 實(shí)現(xiàn)
有興趣可以去瞧瞧虑润,目前oauth2+openId掃碼登錄正在開(kāi)發(fā)中... 歡迎fork添加代碼