前言
-
分析业务
关于抖音APP登录应该有很多人进行过尝试,并且抖音针对APP登录验证码进行多次改进,包括后续出现的需要手机主动发送验证码以及发送手机验证码前出现图形识别验证码等。 -
解决方案
这里我采用的算是抖音目前的一个登录漏洞就是借助企业平台二维码扫码登录,但是这里的企业平台登录并不需要抖音号必须是企业号,也就是说任意的抖音号扫码都能够进行登录无需去发送验证码识别图片等。
开始
分析扫码接口
首先打开抖音企业管理平台https://e.douyin.com/site/
F12查看控制台找到如下两个接口
1.https://e.douyin.com/passport/web/get_qrcode/?next=https:%2F%2Fe.douyin.com%2Fsite&aid=1575
请求参数无需修改。
其中返回参数的含义为:
{
"data": {
"app_name": "抖音App",
"qrcode": "iVBORw0KGgoAAAANSUhEUgAAAgAAAAIAAQMAAADOtka5AAAABlBMVEX///8AAABVwtN+AAAFE0lEQVR42uycPZLjOAyFoXLg0EfQUXw06Wg6io6g0IGL2CLeA+WtUU9vsmUED4lmbOvrgASIX5pEIpFIJBKJRCKRSCT/QTxknd73/mw39/3p/jab3ZvFY/L40G7x0yZAQUD8/7na7fXYbeHD3Y95W9rNj5nwrX83XhCgGiBWfm1m/c3pfT+4OfbnOr073Ckd7r4KUBjg3hd5mdw7YII6p6pjVwhQH9BuL5s3M7sfM4wzfts3RztVXYCqAFjlZnG4hjqHjQ49hjrj4F3/btYF+CqAKhtr/fzl8TcnS4CvAk5Ot7wTeFO30c/V36nc4TH9FrgI8D0ADTBVFl7RyuDk/PCxm+HDVYCKgFjrLf4JP6g//G2P/uv4bgnH1xaEoX8crgLUAOTh2mNMuEpLuLob4Fz5HrjEiWsCFAT0Ny39WA91zg87/MPV5eZoAhQERKiZDtAaEUtX4NfDx3ZAUiFyC7MANQFYZEP+oB+gB/ZBj0bNrHNolZ1/SoCCAFpe/ihfgR5H/mc4Tn1z7FdmXYDvA7oDi0Vm4pV+0MOD2vW4bxWPiOVx4eoKUAHA2lZEnBv2AbJBszv+t6ZxRt62CVATcMA4W2h1ZHxQsESKb2PC/aeIRYAKgL66keoJVzc83uEVseCFiGX9IWIRoAKg4ThlNYuukr/DR/J3Gm5UoeNwbQIUBPQYxcIqww5HxIkzNnZFfwVdBAZ1NgEKAnBy9kU2G6mCqFR2Pb77R08IMg1NgIKAXGTEn5kGQol5ymwsPKZ+DF9YZQEqAHI73NEwcD/zB04FZsTCKlgToCAgylgjtx5pvL4BXsz0ffpICFxMgIIAH+HkAwVnpIHYE8KIMxu1aLEFKAdgbaTB5DIMZYn5bFQ+Rr/IRTZPgO8DwgAjcIlGV2bTowuEjtPZjHWZzROgBMDYcHXMGyqVbEJ/hnLvz3UUw8KNagIUBHTnaB/NIBP6Pho6JKOKmZWuzDSYAAUBp1UeKXbPh0fba3q8PtLvApQDeK78iDFtKLdjiCeLmQhRmwAFAWNeB6MBt9G9THdoZmtIPNy3RYCKAEtbi6IIohJ8vrDSNabueP4KUA/A6QGaXKaBJuwKuEorqtB4CFATEO4sQpUdtRFj4AIDPDuGl3GqXpVIBCgAcOYIRlSJGCXblh9sm8wmys0EqAiIteb0AA/XyOYdwypD4/nmZeFagK8DxiJnF0jmfziu3MMYtPawp8AEqAiAHfbzKg/H1DKq0HYm1dlo0AQoCHB/2TnEk3cIvLOnzvfRi243v9oHAlQAsIw1us9f57zOgrz7kk2w0PEmQEEArTIizjM3m+OuMa6Vp+r9qgtEgAoAtO8sH4ELh0BOr9bxXfthIwlQAMCbHTD9uLK2ZVkbeWXEMuO7q4hFgAIA6vHIuN6ZlM2atG8cMFgYjTYBCgJSSdOrRWsrtBqtISvP2BxsFqAggEXljwsCZq78GOnhEAGcYhegIoDtj+zUST/oxvYrlEjsvFDwz30gQBnA+HbkfyIbxAsh4T/Z+BsC1AOw0pXXzJ23PUbCnc6RH/O/itECVAPk3YGoLXOkddwdiBLl5yi6ADUBvJB1JGXzYquPqVc/+5WvQx4B6gCiC8uz3xVjOxGxnF0gV0lZAYoBeGkZenrsbFs+s7GP3UyAkgDL3+bdnXlpEjtcN/wNFLyupwcE+DrgsycLXVg4QFmi9DH8uiAoXQSoCJBIJBKJRCKRSCQSieR/kX8CAAD//42IIL+TH02AAAAAAElFTkSuQmCC",
"qrcode_index_url": "https://aweme.snssdk.com/passport/web/scan_index/?device_platform=&hide_nav_bar=1&next_url=https%3A%2F%2Faweme.snssdk.com%2Fpassport%2Fweb%2Fscan_qrcode%2F&token=a54f8b5c3d9096078b5ed497c67730c9",
"token": "a54f8b5c3d9096078b5ed497c67730c9",
"web_name": "抖音内容管理平台"
},
"message": "success"
}
参数名 | 含义 |
---|---|
qrcode_index_url | 抖音二维码连接 |
qrcode | 图片base64 |
token | 验证token接口会用到,用于校验扫码状态 |
2.https://e.douyin.com/passport/web/check_qrconnect/?next=https:%2F%2Fe.douyin.com%2Fsite%2F&token=8665aca727570ea2901f1e8173c816eb&aid=1575
请求参数中的token
为1接口中返回的token
其中返回参数的含义为:
接口分为四种返回状态
未扫码
{
"data": {
"status": "new"
},
"message": "success"
}
已扫码未确认
{
"data": {
"status": "scanned"
},
"message": "success"
}
已确认
{
"data": {
"redirect_url": "https://e.douyin.com/site",
"status": "confirmed"
},
"message": "success"
}
二维码过期
{
"data": {
"app_name": "抖音App",
"qrcode": "iVBORw0KGgoAAAANSUhEUgAAAgAAAAIAAQMAAADOtka5AAAABlBMVEX///8AAABVwtN+AAAFGElEQVR42uycPZLrug6EoVKg0EvwUrQ0cWlaipfg0IGLeEV0k9K7oznnJreEoJGobI++CfgHNACaTCaTyWQymUwmk8lk/8I8rEzfpT2rLW9b3b9mz/YpHs1eq9vs+BMB8gHi81ps9vdz3yb/mNnmHp/q7G+zLeD7ZvNnvCBANsDcBrlUwx+ZPXw3jvz0bXCn2fx5uBcBEgPayLchj4dNsZzLxKWO3wTID6jzx557e/PRdl5swG1WvGyr86c9BMgMwK5cYx1vAdgtNuC1cDnj4C1/3tYFuBVAHynGev3L409OlgC3Ak6cdpzCR4pHvPJuHi+Wev1r4CLAbQCMbuF2HKFKW84x5NMRzbyMXxYBMgL8u7xjkPGYEbGMM7YFLu5xuCIM/XG4CpAC0GLMvivHyrW1OUdtOgScI98Cl/GbANkAmACb2RKBC0KV9sAc8Zed5sHjUgYS4H4A3NkS++9uFmpe4Toeji8Cz/avBMgJqFi52I7tLOqtxaANhf9k0PbWIkBGQOg/UPNegXtEjElRKBQDTpX22+t6WxfgbgBHPkRZBifNx403KfG1g9f333ZlATIA+DVWrtEd4gZsmBUTwhgEpSZASkCsXGM4EsJr+LihDWFXprZeO1yAfACsXK/nId/g6uJUXRmxFO8nrgD5ACHu7D3THK4uQpWYDoHrGze1WQESAvwbMcoUMoIP4S7UIBui+iEjXKp5AtwNgOJzLOB4E3kvMzhOk3c3amzOAmQDzEPNO2R0rtyJESc9pgg8ryMWAe4GGCbAt+s/iD+Xfqp2wbaHob8kLAW4F+DfUAUQeIYfFFU8n3/4SM9+1P5MdQqQAMDcFtRYZzEkIxbvEaf3314/d2UBkgCQm/z08isfeeejUPn93K0XSgqQEGBDjbVjrBlj0nGi49sFWwESArjzQo0tzHQhVEGFJF2llVPlsrROgPsB8TX34em79Cqs6AVhpusUxmwmQEKAHYmPyFQ6ZdhTZw8ldqSmBUgJ6IpdxCjIjexWeZxG+cCGMGZjaV0VICGASeXeGjCzUuDD9NebWzUejrylAOkA1qtAUAzZwtARxvQ1Hl9SYjcBMgIcjR6VmRIcrih0RTEImyd58AqQE8AUJcbaWBpZj+6rZ69F36jtmQAJAajJ6n4QFzfOWFRIjjAGU8UEyAgYpZFQYzHkXRRChc8ogrXrYh4B7gdAcS2OYjqbqaYvJzWPzcu1e8MC5AOc6nZGcGmHRMtdOXwkrmoBEgJY6eG9GGvB5R1oXo68M7sHetmPCZAQgGKsUROJkR8FH8sQhXAjy/Oy31mA2wEo8ShIPxf2SQ5R4Wj7WE/angDpAKwCmRxtA1jHlPHO8vvq9XoeCJABwJsdRocAfCS4SuwFoVIbn/ZfLg8Q4F7A4QA1P/b/N2d2hqClLu6HeP4UZQXIAGDCuXbFrl8F8XiddmXeZLag3VWAfACnO4u8JUvr6qh+tX7wxuaMySFAPgB7AkalDvyg040sR2cIqpcFSAugNovyq+fea7IYcR6dkVeXzgmQAUD9p6vp7MxCTRZKe7qrNJLRAuQDHHcHjtJk1kSuyFuy3tzLaGwWICGg3+TJKkh/j8nhNqqXx5fXIY8ASQBd1EOfJFMkbLCbfFzI+lqLAMkBcQXrcm5pPd1dFkotnWIB8gHwt9Oo6UEvZC87Z71We/MMFyAZ4JypjK5zTIdDG2IRJXOal5kuAW4HyGQymUwmk8lkMplM9p/Y/wIAAP//7/XzdgiagFcAAAAASUVORK5CYII=",
"qrcode_index_url": "https://aweme.snssdk.com/passport/web/scan_index/?device_platform=&hide_nav_bar=1&next_url=https%3A%2F%2Faweme.snssdk.com%2Fpassport%2Fweb%2Fscan_qrcode%2F&token=64e2ba4fb22693504a2fd4ab9f64acf4",
"status": "expired",
"token": "64e2ba4fb22693504a2fd4ab9f64acf4",
"web_name": "抖音内容管理平台"
},
"message": "success"
}
参数名 | 含义 |
---|---|
status | 扫码状态(new 未扫码,scanned 已扫码未确认, confirmed 已确认,expired 二维码过期会重新返回二维码信息) |
qrcode | 图片base64 |
redirect_url | 没有什么用 |
这个接口需要轮询调用直到扫码结束
confirmed
状态后停止轮询处理获取Cookie流程
处理Cookie流程
我们可以看到在2接口confirmed
状态中服务端设置了Cookie
接下来就简单了 只需要提取set-cookie
中的值就行了
以下为java
代码的实现方式:
QrcodeLoginService
public class QrcodeLoginService {
/**
* 获取抖音二维码
* @return
*/
public Result getQrcode() {
JSONObject jsonObject = HttpsUtil.urlGet(Constants.QRCODE_URL, null, null, false);
return CommonUtil.successJson(jsonObject.getJSONObject("data"));
}
/**
* 扫码是否成功
* @param token
* @return
*/
public Result check(String token){
JSONObject jsonObject = HttpsUtil.urlGet(Constants.CHECK_QRCONNECT_URL + String.format("&token=%s", token), null, null, true);
JSONObject data = jsonObject.getJSONObject("data");
if (data == null) {
return CommonUtil.errorJson(ErrorEnum.E_20017);
}
String status = data.getString("status");
if (!"confirmed".equals(status)) {
return CommonUtil.errorJson(ErrorEnum.E_20017, data);
}
//获取header
JSONObject headerJson = jsonObject.getJSONObject("header");
//获取Set-Cookie
List<String> lists = JSONObject.parseArray(headerJson.getJSONArray("Set-Cookie").toJSONString(), String.class);
lists = lists.stream().map(v -> v.split(";")[0]).collect(Collectors.toList());
String cookie = StringUtils.join(lists, ";");
// TODO: 拿到Cookie处理自己的登录流程...
}
}
Constants
public final class Constants {
/**
* 获取抖音二维码url
*/
public static final String QRCODE_URL = "https://e.douyin.com/passport/web/get_qrcode/?next=https:%2F%2Fe.douyin.com%2Fsite&aid=1575";
/**
* 验证扫码是否成功
*/
public static final String CHECK_QRCONNECT_URL = "https://e.douyin.com/passport/web/check_qrconnect/?next=https:%2F%2Fe.douyin.com%2Fsite%2F&aid=1575";
}
HttpsUtil
public final class HttpsUtil {
/**
* URLConnection get请求
* @param reqUrl
* @param query
* @param cookie
* @param header true 返回 false 不返回
* @return
*/
public static JSONObject urlGet(String reqUrl, String query, String cookie, boolean header) {
try {
URL url = new URL(StringUtils.isEmpty(query) ? reqUrl : reqUrl + "?" + query);
URLConnection conn = url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
if (!StringUtils.isEmpty(cookie)) {
conn.setRequestProperty("Cookie", cookie);
}
conn.connect();
// 获取输入流
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
JSONObject jsonObject = JSONObject.parseObject(sb.toString());
if (header) {
jsonObject.put("header", conn.getHeaderFields());
}
return jsonObject;
} catch (Exception e) {
log.error(e);
}
return new JSONObject();
}
}
总结
其实简单理解就是抖音企业管理平台的登录与移动端APP登录Cookie信息一致可以实现通用,这样就不需要再去费力的解决移动端的各种验证码的问题了。