如下圖所示,詳解各步驟:
1、用戶請求登錄;
2、請求獲取二維碼。請求地址:https://qrlogin.taobao.com/qrcodelogin/generateQRCode4Login.do?from=alimama,from參數代表來源,本示例演示的是阿里媽媽,其他來源請自行摸索;
3、返回二維碼地址與lgToken。執行第二步操作,淘寶網會返回這樣的JSON:
{
success: true,
message: "null",
url: "//img.alicdn.com/tfscom/TB1Rb1yQpXXXXXTapXXwu0bFXXX.png",
lgToken: "0e7fdfec57971ab22759ef2a0e420afb",
adToken: "1877bc503d6d23555241d4df3b6d6fc7"
}
其中url就是登錄二維碼的地址,lgToken用於后續登錄校驗,其他響應參數請忽略;
4、渲染二維碼,等待用戶掃碼。該步驟主要是將淘寶網返回的二維碼可視化渲染到前台用戶,可以采用網頁展示,也可以本地應用程序方式把二維碼的圖片給呈現出來,等待用戶的掃描操作;
5、根據lgToken,開始登錄狀態驗證。在等待用戶掃描操作的過程中,要同時開始用戶登錄狀態的驗證,該操作是異步執行的。
5.1 先校驗二維碼登錄狀態,二維碼登錄狀態驗證地址:https://qrlogin.taobao.com/qrcodelogin/qrcodeLoginCheck.do,
兩個參數分別是:
defaulturl,其值寫死為:http://login.taobao.com/member/taobaoke/login.htm?is_login=1
lgToken,其值為第2步返回的lgToken值。
循環請求校驗地址,每次請求都會返回類似下面的json:
{"code":"10000","message":"login start state","success":true}
其中,code=10004表示二維碼已過期;code=10006會返回url,表示用戶掃碼確認登錄
5.2 當code=10006,獲取url,帶上返回的cookie請求該url。特別注意,淘寶網為進行不同站點的session同步,會存在多次302的跳轉操作,所以,請不停的跳轉直至該請求返回200
6、用戶掃碼並確認登錄。用戶掃碼確認,會發送請求給淘寶。
7、淘寶網接到確認掃碼,返回登錄成功。
8、保存登錄Cookie信息
9、提示用戶登錄成功
展示一部分Java的代碼片段:
public void checkAndSetLoginStatus(String lgToken) { Thread thread = new Thread(new Runnable() { @Override public void run() { Map<String, String> params = newHashMap(); params.put("defaulturl", "http://login.taobao.com/member/taobaoke/login.htm?is_login=1 params.put("lgToken", lgToken); int retryTimes = 1; HttpResponse loginCheckResp =HttpUtil.post("https://qrlogin.taobao.com/qrcodelogin/qrcodeLoginCheck.do null); QRcodeLoginCheck loginCheck =JSON.parseObject(loginCheckResp.getResponse(), QRcodeLoginCheck.class); while (!loginCheck.isLoginSuccess()) { if(loginCheck.isExpire() || retryTimes++>30){ redisService.set(loginKey, QRCODE_EXPIRED+""); log.warn("Taobao login QRCode is expire or long time no scan."); return; } ThreadSleep.sleep(1500); loginCheckResp =HttpUtil.post("https://qrlogin.taobao.com/qrcodelogin/qrcodeLoginCheck.do null); loginCheck =JSON.parseObject(loginCheckResp.getResponse(), QRcodeLoginCheck.class); } HttpResponse httpResponse = HttpUtil.post(loginCheck.getUrl(), loginCheckResp.getCookieStore()); while(httpResponse != null && httpResponse.is302Direct()){ String location = httpResponse.getLocaltion(); httpResponse = HttpUtil.post(location, httpResponse.getCookieStore()); } byte[] data = new JavaSerializer().to(httpResponse.getCookieStore()); redisService.set(sessionKey, Base64.encodeBase64String(data)); } }); thread.setName("TB_Login_Thread"); thread.start(); }