登入失败禁止登入
This commit is contained in:
@@ -46,7 +46,9 @@ public class CrawlerSchedule {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String token = tokenCacheService.getToken();
|
String token = tokenCacheService.getToken();
|
||||||
|
if (token == null || token.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
while (!success && retryCount < MAX_CRA) {
|
while (!success && retryCount < MAX_CRA) {
|
||||||
log.info("\n=== 第 " + (retryCount + 1) + " 次尝试获取开奖结果 ===");
|
log.info("\n=== 第 " + (retryCount + 1) + " 次尝试获取开奖结果 ===");
|
||||||
if (token == null || token.isEmpty()) {
|
if (token == null || token.isEmpty()) {
|
||||||
@@ -123,7 +125,9 @@ public class CrawlerSchedule {
|
|||||||
int retryCount = 0;
|
int retryCount = 0;
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
String token = tokenCacheService.getToken();
|
String token = tokenCacheService.getToken();
|
||||||
|
if (token == null || token.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
while (!success && retryCount < MAX_CRA) {
|
while (!success && retryCount < MAX_CRA) {
|
||||||
log.info("\n=== 第 " + (retryCount + 1) + " 次尝试获取今日注单 ===");
|
log.info("\n=== 第 " + (retryCount + 1) + " 次尝试获取今日注单 ===");
|
||||||
if (token == null || token.isEmpty()) {
|
if (token == null || token.isEmpty()) {
|
||||||
|
|||||||
@@ -1,282 +0,0 @@
|
|||||||
package com.tem.bocai.util;
|
|
||||||
|
|
||||||
import net.sourceforge.tess4j.Tesseract;
|
|
||||||
import net.sourceforge.tess4j.TesseractException;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.http.Header;
|
|
||||||
import org.apache.http.NameValuePair;
|
|
||||||
import org.apache.http.client.CookieStore;
|
|
||||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
|
||||||
import org.apache.http.client.methods.*;
|
|
||||||
import org.apache.http.impl.client.BasicCookieStore;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.apache.http.impl.client.HttpClients;
|
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
|
||||||
import org.apache.http.util.EntityUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.core.io.ResourceLoader;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
|
||||||
import org.apache.http.client.methods.HttpPost;
|
|
||||||
|
|
||||||
import org.apache.http.client.config.RequestConfig;
|
|
||||||
import org.apache.http.cookie.Cookie;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class ImageOcrService {
|
|
||||||
|
|
||||||
private final Tesseract tesseract;
|
|
||||||
private final ResourceLoader resourceLoader;
|
|
||||||
private static CloseableHttpClient httpClient;
|
|
||||||
private static final String BASE_URL = "https://4701268539-esh.qdk63ayw8g.com";
|
|
||||||
@Autowired
|
|
||||||
public ImageOcrService(Tesseract tesseract, ResourceLoader resourceLoader) {
|
|
||||||
|
|
||||||
this.tesseract = tesseract;
|
|
||||||
this.resourceLoader = resourceLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从本地文件路径读取图片并进行 OCR 处理
|
|
||||||
*
|
|
||||||
* @param imagePath 图片文件路径
|
|
||||||
* @return OCR 结果文本
|
|
||||||
*/
|
|
||||||
public String ocrLocalImage(String imagePath) throws IOException, TesseractException {
|
|
||||||
|
|
||||||
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(imagePath);
|
|
||||||
BufferedImage image = ImageIO.read(inputStream);
|
|
||||||
return tesseract.doOCR(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从远程 URL 获取图片并进行 OCR 处理
|
|
||||||
*
|
|
||||||
* @return OCR 结果文本
|
|
||||||
*/
|
|
||||||
public String ocrRemoteImage() throws IOException, TesseractException, InterruptedException {
|
|
||||||
int maxRetry = 5;
|
|
||||||
|
|
||||||
for (int attempt = 1; attempt <= maxRetry; attempt++) {
|
|
||||||
System.out.println("\n=== 第 " + attempt + " 次尝试 ===");
|
|
||||||
|
|
||||||
// 每次尝试都创建新的HttpClient和CookieStore
|
|
||||||
CookieStore cookieStore = new BasicCookieStore();
|
|
||||||
CloseableHttpClient httpClient = HttpClients.custom()
|
|
||||||
.setDefaultCookieStore(cookieStore)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 1. 获取验证码
|
|
||||||
System.out.println("获取验证码...");
|
|
||||||
HttpGet getCaptcha = new HttpGet(BASE_URL + "/code");
|
|
||||||
setCommonHeaders(getCaptcha);
|
|
||||||
// 添加Referer头
|
|
||||||
getCaptcha.setHeader("Referer", BASE_URL + "/login");
|
|
||||||
// 添加随机延迟,避免请求过快
|
|
||||||
Thread.sleep(1000 + (long)(Math.random() * 1000));
|
|
||||||
|
|
||||||
CloseableHttpResponse captchaResponse = httpClient.execute(getCaptcha);
|
|
||||||
byte[] imageData = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
int captchaStatus = captchaResponse.getStatusLine().getStatusCode();
|
|
||||||
System.out.println("验证码响应状态码: " + captchaStatus);
|
|
||||||
|
|
||||||
if (captchaStatus == 200) {
|
|
||||||
imageData = EntityUtils.toByteArray(captchaResponse.getEntity());
|
|
||||||
} else if (captchaStatus == 429) {
|
|
||||||
System.out.println("获取验证码被限速,等待后重试...");
|
|
||||||
Thread.sleep(3000); // 等待3秒
|
|
||||||
continue; // 继续下一次尝试
|
|
||||||
} else {
|
|
||||||
System.out.println("获取验证码失败: " + captchaStatus);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
captchaResponse.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. OCR识别验证码
|
|
||||||
String code = null;
|
|
||||||
if (imageData != null) {
|
|
||||||
BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageData));
|
|
||||||
code = tesseract.doOCR(image);
|
|
||||||
|
|
||||||
// 清理验证码
|
|
||||||
code = code.replaceAll("\\s+", "").trim();
|
|
||||||
code = code.replaceAll("[^0-9]", ""); // 只保留数字
|
|
||||||
|
|
||||||
System.out.println("OCR原始结果: " + tesseract.doOCR(image));
|
|
||||||
System.out.println("清理后验证码: [" + code + "] 长度: " + code.length());
|
|
||||||
|
|
||||||
// 保存图片用于调试
|
|
||||||
File output = new File("captcha_attempt_" + attempt + ".png");
|
|
||||||
ImageIO.write(image, "png", output);
|
|
||||||
System.out.println("验证码图片已保存到: " + output.getAbsolutePath());
|
|
||||||
|
|
||||||
if (code.length() != 4) {
|
|
||||||
System.out.println("验证码长度不是4位,跳过本次尝试");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
System.out.println("验证码数据为空");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待一下再发送登录请求
|
|
||||||
Thread.sleep(1500 + (long)(Math.random() * 1000));
|
|
||||||
|
|
||||||
// 3. 登录(不自动重定向)
|
|
||||||
System.out.println("执行登录...");
|
|
||||||
HttpPost loginPost = new HttpPost(BASE_URL + "/login");
|
|
||||||
setCommonHeaders(loginPost);
|
|
||||||
// 重要:添加Referer和Origin头
|
|
||||||
loginPost.setHeader("Referer", BASE_URL + "/login");
|
|
||||||
loginPost.setHeader("Origin", BASE_URL);
|
|
||||||
loginPost.setHeader("Accept", "application/json, text/plain, */*");
|
|
||||||
// 构建登录参数
|
|
||||||
List<NameValuePair> params = new ArrayList<>();
|
|
||||||
params.add(new BasicNameValuePair("type", "1"));
|
|
||||||
params.add(new BasicNameValuePair("account", "pmk1"));
|
|
||||||
params.add(new BasicNameValuePair("password", "Asd123123"));
|
|
||||||
params.add(new BasicNameValuePair("code", code));
|
|
||||||
loginPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
|
||||||
// 禁用自动重定向
|
|
||||||
RequestConfig requestConfig = RequestConfig.custom()
|
|
||||||
.setRedirectsEnabled(false)
|
|
||||||
.build();
|
|
||||||
loginPost.setConfig(requestConfig);
|
|
||||||
CloseableHttpResponse loginResponse = httpClient.execute(loginPost);
|
|
||||||
try {
|
|
||||||
int statusCode = loginResponse.getStatusLine().getStatusCode();
|
|
||||||
System.out.println("登录响应状态码: " + statusCode);
|
|
||||||
|
|
||||||
// 处理429错误
|
|
||||||
if (statusCode == 429) {
|
|
||||||
System.out.println("登录请求被限速 (429 Too Many Requests)");
|
|
||||||
|
|
||||||
// 检查Retry-After头
|
|
||||||
Header retryAfterHeader = loginResponse.getFirstHeader("Retry-After");
|
|
||||||
if (retryAfterHeader != null) {
|
|
||||||
try {
|
|
||||||
int retryAfterSeconds = Integer.parseInt(retryAfterHeader.getValue());
|
|
||||||
System.out.println("服务器要求等待 " + retryAfterSeconds + " 秒");
|
|
||||||
Thread.sleep(retryAfterSeconds * 1000L);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
System.out.println("等待5秒后重试");
|
|
||||||
Thread.sleep(5000);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
System.out.println("等待3秒后重试");
|
|
||||||
Thread.sleep(3000);
|
|
||||||
}
|
|
||||||
continue; // 继续下一次尝试
|
|
||||||
}
|
|
||||||
// 打印响应头
|
|
||||||
System.out.println("响应头:");
|
|
||||||
for (Header header : loginResponse.getAllHeaders()) {
|
|
||||||
System.out.println(" " + header.getName() + ": " + header.getValue());
|
|
||||||
}
|
|
||||||
// 检查是否是重定向
|
|
||||||
if (statusCode == 302) {
|
|
||||||
Header locationHeader = loginResponse.getFirstHeader("Location");
|
|
||||||
if (locationHeader != null) {
|
|
||||||
String location = locationHeader.getValue();
|
|
||||||
System.out.println("重定向到: " + location);
|
|
||||||
|
|
||||||
if (location.contains("e=3")) {
|
|
||||||
System.out.println("验证码错误 (e=3)");
|
|
||||||
continue; // 继续下一次尝试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 读取响应体(如果有)
|
|
||||||
if (loginResponse.getEntity() != null) {
|
|
||||||
String responseBody = EntityUtils.toString(loginResponse.getEntity(), "UTF-8");
|
|
||||||
if (responseBody != null && !responseBody.isEmpty()) {
|
|
||||||
System.out.println("响应体: " + responseBody);
|
|
||||||
|
|
||||||
// 检查响应体中是否有token(JSON格式)
|
|
||||||
if (responseBody.contains("\"token\"")) {
|
|
||||||
// 简单提取token
|
|
||||||
int start = responseBody.indexOf("\"token\":\"");
|
|
||||||
if (start != -1) {
|
|
||||||
start += 9;
|
|
||||||
int end = responseBody.indexOf("\"", start);
|
|
||||||
if (end != -1) {
|
|
||||||
String token = responseBody.substring(start, end);
|
|
||||||
System.out.println("\n[SUCCESS] 从响应体找到Token!");
|
|
||||||
System.out.println("Token: " + token);
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 消耗实体
|
|
||||||
EntityUtils.consume(loginResponse.getEntity());
|
|
||||||
}
|
|
||||||
// 4. 检查cookies中是否有token
|
|
||||||
String token = null;
|
|
||||||
List<Cookie> cookies = cookieStore.getCookies();
|
|
||||||
System.out.println("所有cookies (" + cookies.size() + "个):");
|
|
||||||
for (Cookie cookie : cookies) {
|
|
||||||
System.out.println(" " + cookie.getName() + " = " + cookie.getValue());
|
|
||||||
|
|
||||||
// 查找token
|
|
||||||
if ("token".equals(cookie.getName()) ||
|
|
||||||
cookie.getName().toLowerCase().contains("token")) {
|
|
||||||
token = cookie.getValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token != null && !token.isEmpty()) {
|
|
||||||
System.out.println("\n[SUCCESS] Login OK!");
|
|
||||||
System.out.println("Token: " + token);
|
|
||||||
return token;
|
|
||||||
} else if (statusCode == 200) {
|
|
||||||
// 如果是200状态码但没有token,可能是登录成功但token在其他地方
|
|
||||||
System.out.println("登录返回200但没有找到token,可能需要检查其他认证方式");
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
loginResponse.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
httpClient.close();
|
|
||||||
}
|
|
||||||
// 如果不是最后一次尝试,等待一段时间
|
|
||||||
if (attempt < maxRetry) {
|
|
||||||
System.out.println("\n等待2秒后进行下一次尝试...");
|
|
||||||
Thread.sleep(2000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("\n[FAILED] " + maxRetry + " 次尝试都失败了");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setCommonHeaders(HttpRequestBase request) {
|
|
||||||
request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
|
|
||||||
request.setHeader("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
|
|
||||||
request.setHeader("Accept-Encoding", "gzip, deflate, br");
|
|
||||||
request.setHeader("Connection", "keep-alive");
|
|
||||||
request.setHeader("Upgrade-Insecure-Requests", "1");
|
|
||||||
request.setHeader("Sec-Fetch-Dest", "document");
|
|
||||||
request.setHeader("Sec-Fetch-Mode", "navigate");
|
|
||||||
request.setHeader("Sec-Fetch-Site", "same-origin");
|
|
||||||
request.setHeader("Sec-Fetch-User", "?1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ import com.tem.bocai.param.LoginInfoParam;
|
|||||||
import com.tem.bocai.repository.LoginInfoRepository;
|
import com.tem.bocai.repository.LoginInfoRepository;
|
||||||
import com.tem.bocai.service.LoginService;
|
import com.tem.bocai.service.LoginService;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.sourceforge.tess4j.Tesseract;
|
import net.sourceforge.tess4j.Tesseract;
|
||||||
import net.sourceforge.tess4j.TesseractException;
|
import net.sourceforge.tess4j.TesseractException;
|
||||||
import org.apache.http.Header;
|
import org.apache.http.Header;
|
||||||
@@ -35,7 +36,9 @@ import java.io.UnsupportedEncodingException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class TokenCacheService {
|
public class TokenCacheService {
|
||||||
|
|
||||||
@@ -44,12 +47,19 @@ public class TokenCacheService {
|
|||||||
private static final String TOKEN_INFO_KEY = "token_info";
|
private static final String TOKEN_INFO_KEY = "token_info";
|
||||||
private static final int MAX_RETRY = 10;
|
private static final int MAX_RETRY = 10;
|
||||||
private static final String BASE_URL = "https://4701268539-esh.qdk63ayw8g.com";
|
private static final String BASE_URL = "https://4701268539-esh.qdk63ayw8g.com";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private Tesseract tesseract;
|
private Tesseract tesseract;
|
||||||
@Autowired
|
@Autowired
|
||||||
private CacheManager tokenCacheManager;
|
private CacheManager tokenCacheManager;
|
||||||
@Autowired
|
@Autowired
|
||||||
private LoginInfoRepository loginInfoRepository;
|
private LoginInfoRepository loginInfoRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许登录的标志 - 密码错误一次就禁止
|
||||||
|
*/
|
||||||
|
private volatile boolean loginEnabled = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存token到缓存
|
* 保存token到缓存
|
||||||
*/
|
*/
|
||||||
@@ -57,7 +67,7 @@ public class TokenCacheService {
|
|||||||
Cache cache = tokenCacheManager.getCache(TOKEN_CACHE_NAME);
|
Cache cache = tokenCacheManager.getCache(TOKEN_CACHE_NAME);
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
cache.put(TOKEN_KEY, token);
|
cache.put(TOKEN_KEY, token);
|
||||||
System.out.println("Token已保存到内存缓存");
|
log.info("Token已保存到内存缓存");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,17 +75,23 @@ public class TokenCacheService {
|
|||||||
* 从缓存获取token
|
* 从缓存获取token
|
||||||
*/
|
*/
|
||||||
public String getToken() {
|
public String getToken() {
|
||||||
|
// 检查是否允许登录
|
||||||
|
if (!loginEnabled) {
|
||||||
|
log.info("账号密码错误,已禁止登录");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
Cache cache = tokenCacheManager.getCache(TOKEN_CACHE_NAME);
|
Cache cache = tokenCacheManager.getCache(TOKEN_CACHE_NAME);
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
String token = cache.get(TOKEN_KEY, String.class);
|
String token = cache.get(TOKEN_KEY, String.class);
|
||||||
if (token != null && !token.isEmpty()) {
|
if (token != null && !token.isEmpty()) {
|
||||||
System.out.println("从缓存获取到token");
|
log.info("从缓存获取到token");
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 缓存不存在或token为空时,从SQLite获取
|
// 缓存不存在或token为空时,从SQLite获取
|
||||||
String token = getTokenSqlite();
|
String token = getTokenSqlite();
|
||||||
System.out.println("重新登入获取的token==" + token);
|
log.info("重新登入获取的token: {}", token);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +99,12 @@ public class TokenCacheService {
|
|||||||
* 从缓存获取token,如果不存在则通过回调函数获取
|
* 从缓存获取token,如果不存在则通过回调函数获取
|
||||||
*/
|
*/
|
||||||
public String getToken(Callable<String> tokenLoader) {
|
public String getToken(Callable<String> tokenLoader) {
|
||||||
|
// 检查是否允许登录
|
||||||
|
if (!loginEnabled) {
|
||||||
|
log.info("账号密码错误,已禁止登录");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
Cache cache = tokenCacheManager.getCache(TOKEN_CACHE_NAME);
|
Cache cache = tokenCacheManager.getCache(TOKEN_CACHE_NAME);
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
return cache.get(TOKEN_KEY, tokenLoader);
|
return cache.get(TOKEN_KEY, tokenLoader);
|
||||||
@@ -97,7 +119,7 @@ public class TokenCacheService {
|
|||||||
Cache cache = tokenCacheManager.getCache(TOKEN_CACHE_NAME);
|
Cache cache = tokenCacheManager.getCache(TOKEN_CACHE_NAME);
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
cache.evict(TOKEN_KEY);
|
cache.evict(TOKEN_KEY);
|
||||||
System.out.println("Token已从内存缓存清除");
|
log.info("Token已从内存缓存清除");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +127,10 @@ public class TokenCacheService {
|
|||||||
* 检查是否有有效token
|
* 检查是否有有效token
|
||||||
*/
|
*/
|
||||||
public boolean hasValidToken() {
|
public boolean hasValidToken() {
|
||||||
|
// 检查是否允许登录
|
||||||
|
if (!loginEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return getToken() != null;
|
return getToken() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,20 +155,78 @@ public class TokenCacheService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录账号密码错误 - 密码错误一次就禁止
|
||||||
|
*/
|
||||||
|
private void recordAccountPasswordError() {
|
||||||
|
loginEnabled = false;
|
||||||
|
log.info("账号密码错误,禁止登录");
|
||||||
|
// 清除缓存中的token,避免使用旧的token
|
||||||
|
clearToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置账号密码错误计数
|
||||||
|
*/
|
||||||
|
private void resetAccountPasswordError() {
|
||||||
|
loginEnabled = true;
|
||||||
|
log.info("登录状态已重置,可以重新登录");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部重置登录状态的方法
|
||||||
|
*/
|
||||||
|
public void resetLoginStatus() {
|
||||||
|
resetAccountPasswordError();
|
||||||
|
log.info("登录状态已重置,可以重新登录");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否允许登录
|
||||||
|
*/
|
||||||
|
public boolean isLoginEnabled() {
|
||||||
|
return loginEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取登录状态描述
|
||||||
|
*/
|
||||||
|
public String getLoginStatus() {
|
||||||
|
return loginEnabled ? "登录已启用" : "账号密码错误,登录已禁用";
|
||||||
|
}
|
||||||
|
|
||||||
public String getTokenSqlite() {
|
public String getTokenSqlite() {
|
||||||
|
// 检查是否允许登录
|
||||||
|
if (!loginEnabled) {
|
||||||
|
log.info("账号密码错误,已禁止登录");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
String token = "";
|
String token = "";
|
||||||
for (int attempt = 1; attempt <= MAX_RETRY; attempt++) {
|
for (int attempt = 1; attempt <= MAX_RETRY; attempt++) {
|
||||||
System.out.println("\n=== 第 " + attempt + " 次尝试 ===");
|
// 每次循环开始前检查登录状态
|
||||||
|
if (!loginEnabled) {
|
||||||
|
log.info("账号密码错误,已禁止登录,停止尝试");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("\n=== 第 {} 次尝试 ===", attempt);
|
||||||
try {
|
try {
|
||||||
LoginInfoResult firstByOrderByCreateTimeDesc = loginInfoRepository.findFirstByOrderByCreateTimeDesc()
|
LoginInfoResult firstByOrderByCreateTimeDesc = loginInfoRepository.findFirstByOrderByCreateTimeDesc()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
if (firstByOrderByCreateTimeDesc == null) {
|
||||||
|
log.error("未找到登录信息");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
LoginInfoParam loginInfoParam = new LoginInfoParam();
|
LoginInfoParam loginInfoParam = new LoginInfoParam();
|
||||||
loginInfoParam.setUsername(firstByOrderByCreateTimeDesc.getUsername());
|
loginInfoParam.setUsername(firstByOrderByCreateTimeDesc.getUsername());
|
||||||
loginInfoParam.setPassword(firstByOrderByCreateTimeDesc.getPassword());
|
loginInfoParam.setPassword(firstByOrderByCreateTimeDesc.getPassword());
|
||||||
loginInfoParam.setLoginUrl(firstByOrderByCreateTimeDesc.getLoginUrl());
|
loginInfoParam.setLoginUrl(firstByOrderByCreateTimeDesc.getLoginUrl());
|
||||||
token = attemptLogin(loginInfoParam);
|
token = attemptLogin(loginInfoParam);
|
||||||
if (token != null && !token.isEmpty()) {
|
if (token != null && !token.isEmpty()) {
|
||||||
|
// 登录成功,重置错误计数
|
||||||
|
resetAccountPasswordError();
|
||||||
//保存缓存token
|
//保存缓存token
|
||||||
saveToken(token);
|
saveToken(token);
|
||||||
return token;
|
return token;
|
||||||
@@ -151,8 +235,12 @@ public class TokenCacheService {
|
|||||||
waitForRetry(attempt);
|
waitForRetry(attempt);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("第 " + attempt + " 次尝试失败: " + e.getMessage());
|
log.error("第 {} 次尝试失败: {}", attempt, e.getMessage(), e);
|
||||||
e.printStackTrace();
|
// 检查是否因为密码错误导致禁止登录
|
||||||
|
if (!loginEnabled) {
|
||||||
|
log.info("检测到账号密码错误,停止尝试");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
@@ -162,7 +250,7 @@ public class TokenCacheService {
|
|||||||
* 等待重试
|
* 等待重试
|
||||||
*/
|
*/
|
||||||
public void waitForRetry(int attempt) throws InterruptedException {
|
public void waitForRetry(int attempt) throws InterruptedException {
|
||||||
System.out.println("\n等待2秒后进行下一次尝试...");
|
log.info("\n等待2秒后进行下一次尝试...");
|
||||||
Thread.sleep(2000);
|
Thread.sleep(2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +274,7 @@ public class TokenCacheService {
|
|||||||
return performLogin(httpClient, cookieStore, code,loginInfoParam);
|
return performLogin(httpClient, cookieStore, code,loginInfoParam);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("登录尝试失败" + e);
|
log.error("登录尝试失败", e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -207,7 +295,7 @@ public class TokenCacheService {
|
|||||||
private byte[] fetchCaptcha(CloseableHttpClient httpClient)
|
private byte[] fetchCaptcha(CloseableHttpClient httpClient)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
|
|
||||||
System.out.println("获取验证码...");
|
log.info("获取验证码...");
|
||||||
|
|
||||||
// 添加随机延迟
|
// 添加随机延迟
|
||||||
Thread.sleep(1000 + (long) (Math.random() * 1000));
|
Thread.sleep(1000 + (long) (Math.random() * 1000));
|
||||||
@@ -218,15 +306,15 @@ public class TokenCacheService {
|
|||||||
|
|
||||||
try (CloseableHttpResponse captchaResponse = httpClient.execute(getCaptcha)) {
|
try (CloseableHttpResponse captchaResponse = httpClient.execute(getCaptcha)) {
|
||||||
int captchaStatus = captchaResponse.getStatusLine().getStatusCode();
|
int captchaStatus = captchaResponse.getStatusLine().getStatusCode();
|
||||||
System.out.println("验证码响应状态码: " + captchaStatus);
|
log.info("验证码响应状态码: {}", captchaStatus);
|
||||||
|
|
||||||
if (captchaStatus == 200) {
|
if (captchaStatus == 200) {
|
||||||
return EntityUtils.toByteArray(captchaResponse.getEntity());
|
return EntityUtils.toByteArray(captchaResponse.getEntity());
|
||||||
} else if (captchaStatus == 429) {
|
} else if (captchaStatus == 429) {
|
||||||
System.out.println("获取验证码被限速,等待后重试...");
|
log.info("获取验证码被限速,等待后重试...");
|
||||||
Thread.sleep(3000);
|
Thread.sleep(3000);
|
||||||
} else {
|
} else {
|
||||||
System.out.println("获取验证码失败: " + captchaStatus);
|
log.info("获取验证码失败: {}", captchaStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,8 +333,8 @@ public class TokenCacheService {
|
|||||||
// 清理验证码
|
// 清理验证码
|
||||||
String code = rawOcr.replaceAll("\\s+", "").trim();
|
String code = rawOcr.replaceAll("\\s+", "").trim();
|
||||||
code = code.replaceAll("[^0-9]", ""); // 只保留数字
|
code = code.replaceAll("[^0-9]", ""); // 只保留数字
|
||||||
System.out.println("OCR原始结果: " + rawOcr);
|
log.info("OCR原始结果: {}", rawOcr);
|
||||||
System.out.println("清理后验证码: [" + code + "] 长度: " + code.length());
|
log.info("清理后验证码: [{}] 长度: {}", code, code.length());
|
||||||
// 保存图片用于调试
|
// 保存图片用于调试
|
||||||
//saveCaptchaImage(image);
|
//saveCaptchaImage(image);
|
||||||
|
|
||||||
@@ -270,7 +358,7 @@ public class TokenCacheService {
|
|||||||
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||||
File output = new File("captcha_" + timestamp + ".png");
|
File output = new File("captcha_" + timestamp + ".png");
|
||||||
ImageIO.write(image, "png", output);
|
ImageIO.write(image, "png", output);
|
||||||
System.out.println("验证码图片已保存到: " + output.getAbsolutePath());
|
log.info("验证码图片已保存到: {}", output.getAbsolutePath());
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -280,7 +368,7 @@ public class TokenCacheService {
|
|||||||
CookieStore cookieStore,
|
CookieStore cookieStore,
|
||||||
String code,LoginInfoParam loginInfoParam) throws IOException, InterruptedException {
|
String code,LoginInfoParam loginInfoParam) throws IOException, InterruptedException {
|
||||||
|
|
||||||
System.out.println("执行登录...");
|
log.info("执行登录...");
|
||||||
// 等待一下再发送登录请求
|
// 等待一下再发送登录请求
|
||||||
Thread.sleep(1500 + (long) (Math.random() * 1000));
|
Thread.sleep(1500 + (long) (Math.random() * 1000));
|
||||||
|
|
||||||
@@ -296,7 +384,6 @@ public class TokenCacheService {
|
|||||||
*/
|
*/
|
||||||
private HttpPost createLoginRequest(String code,LoginInfoParam loginInfoParam) throws UnsupportedEncodingException {
|
private HttpPost createLoginRequest(String code,LoginInfoParam loginInfoParam) throws UnsupportedEncodingException {
|
||||||
HttpPost loginPost = new HttpPost(loginInfoParam.loginUrl + "/login");
|
HttpPost loginPost = new HttpPost(loginInfoParam.loginUrl + "/login");
|
||||||
|
|
||||||
// 设置请求头
|
// 设置请求头
|
||||||
setCommonHeaders(loginPost);
|
setCommonHeaders(loginPost);
|
||||||
loginPost.setHeader("Referer", loginInfoParam.loginUrl + "/login");
|
loginPost.setHeader("Referer", loginInfoParam.loginUrl + "/login");
|
||||||
@@ -328,7 +415,7 @@ public class TokenCacheService {
|
|||||||
CookieStore cookieStore) {
|
CookieStore cookieStore) {
|
||||||
try {
|
try {
|
||||||
int statusCode = loginResponse.getStatusLine().getStatusCode();
|
int statusCode = loginResponse.getStatusLine().getStatusCode();
|
||||||
System.out.println("登录响应状态码: " + statusCode);
|
log.info("登录响应状态码: {}", statusCode);
|
||||||
|
|
||||||
// 处理限速
|
// 处理限速
|
||||||
if (statusCode == 429) {
|
if (statusCode == 429) {
|
||||||
@@ -355,7 +442,7 @@ public class TokenCacheService {
|
|||||||
// 从cookies中提取token
|
// 从cookies中提取token
|
||||||
return extractTokenFromCookies(cookieStore, statusCode);
|
return extractTokenFromCookies(cookieStore, statusCode);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("请求异常" + e);
|
log.error("请求异常", e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -364,9 +451,9 @@ public class TokenCacheService {
|
|||||||
* 打印响应头
|
* 打印响应头
|
||||||
*/
|
*/
|
||||||
private void printResponseHeaders(CloseableHttpResponse response) {
|
private void printResponseHeaders(CloseableHttpResponse response) {
|
||||||
System.out.println("响应头:");
|
log.info("响应头:");
|
||||||
for (Header header : response.getAllHeaders()) {
|
for (Header header : response.getAllHeaders()) {
|
||||||
System.out.println(" " + header.getName() + ": " + header.getValue());
|
log.info(" {}: {}", header.getName(), header.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,10 +464,17 @@ public class TokenCacheService {
|
|||||||
Header locationHeader = response.getFirstHeader("Location");
|
Header locationHeader = response.getFirstHeader("Location");
|
||||||
if (locationHeader != null) {
|
if (locationHeader != null) {
|
||||||
String location = locationHeader.getValue();
|
String location = locationHeader.getValue();
|
||||||
System.out.println("重定向到: " + location);
|
log.info("重定向到: {}", location);
|
||||||
|
|
||||||
|
if (location.contains("e=4")) {
|
||||||
|
log.info("账号密码错误 (e=4)");
|
||||||
|
// 记录账号密码错误 - 密码错误一次就禁止
|
||||||
|
recordAccountPasswordError();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (location.contains("e=3")) {
|
if (location.contains("e=3")) {
|
||||||
System.out.println("验证码错误 (e=3)");
|
log.info("验证码错误 (e=3)");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -392,11 +486,11 @@ public class TokenCacheService {
|
|||||||
*/
|
*/
|
||||||
private String extractTokenFromCookies(CookieStore cookieStore, int statusCode) {
|
private String extractTokenFromCookies(CookieStore cookieStore, int statusCode) {
|
||||||
List<Cookie> cookies = cookieStore.getCookies();
|
List<Cookie> cookies = cookieStore.getCookies();
|
||||||
System.out.println("所有cookies (" + cookies.size() + "个):");
|
log.info("所有cookies ({}个):", cookies.size());
|
||||||
|
|
||||||
String token = null;
|
String token = null;
|
||||||
for (Cookie cookie : cookies) {
|
for (Cookie cookie : cookies) {
|
||||||
System.out.println(" " + cookie.getName() + " = " + cookie.getValue());
|
log.info(" {} = {}", cookie.getName(), cookie.getValue());
|
||||||
|
|
||||||
if ("token".equals(cookie.getName()) ||
|
if ("token".equals(cookie.getName()) ||
|
||||||
cookie.getName().toLowerCase().contains("token")) {
|
cookie.getName().toLowerCase().contains("token")) {
|
||||||
@@ -405,11 +499,11 @@ public class TokenCacheService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (token != null && !token.isEmpty()) {
|
if (token != null && !token.isEmpty()) {
|
||||||
System.out.println("\n[SUCCESS] Login OK!");
|
log.info("\n[SUCCESS] Login OK!");
|
||||||
System.out.println("Token: " + token);
|
log.info("Token: {}", token);
|
||||||
return token;
|
return token;
|
||||||
} else if (statusCode == 200) {
|
} else if (statusCode == 200) {
|
||||||
System.out.println("登录返回200但没有找到token,可能需要检查其他认证方式");
|
log.info("登录返回200但没有找到token,可能需要检查其他认证方式");
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -423,7 +517,7 @@ public class TokenCacheService {
|
|||||||
if (response.getEntity() != null) {
|
if (response.getEntity() != null) {
|
||||||
String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8");
|
String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8");
|
||||||
if (responseBody != null && !responseBody.isEmpty()) {
|
if (responseBody != null && !responseBody.isEmpty()) {
|
||||||
System.out.println("响应体: " + responseBody);
|
log.info("响应体: {}", responseBody);
|
||||||
|
|
||||||
// 检查响应体中是否有token(JSON格式)
|
// 检查响应体中是否有token(JSON格式)
|
||||||
if (responseBody.contains("\"token\"")) {
|
if (responseBody.contains("\"token\"")) {
|
||||||
@@ -434,8 +528,8 @@ public class TokenCacheService {
|
|||||||
int end = responseBody.indexOf("\"", start);
|
int end = responseBody.indexOf("\"", start);
|
||||||
if (end != -1) {
|
if (end != -1) {
|
||||||
String token = responseBody.substring(start, end);
|
String token = responseBody.substring(start, end);
|
||||||
System.out.println("\n[SUCCESS] 从响应体找到Token!");
|
log.info("\n[SUCCESS] 从响应体找到Token!");
|
||||||
System.out.println("Token: " + token);
|
log.info("Token: {}", token);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -451,20 +545,20 @@ public class TokenCacheService {
|
|||||||
* 处理速率限制
|
* 处理速率限制
|
||||||
*/
|
*/
|
||||||
private void handleRateLimit(CloseableHttpResponse response) throws InterruptedException {
|
private void handleRateLimit(CloseableHttpResponse response) throws InterruptedException {
|
||||||
System.out.println("登录请求被限速 (429 Too Many Requests)");
|
log.info("登录请求被限速 (429 Too Many Requests)");
|
||||||
|
|
||||||
Header retryAfterHeader = response.getFirstHeader("Retry-After");
|
Header retryAfterHeader = response.getFirstHeader("Retry-After");
|
||||||
if (retryAfterHeader != null) {
|
if (retryAfterHeader != null) {
|
||||||
try {
|
try {
|
||||||
int retryAfterSeconds = Integer.parseInt(retryAfterHeader.getValue());
|
int retryAfterSeconds = Integer.parseInt(retryAfterHeader.getValue());
|
||||||
System.out.println("服务器要求等待 " + retryAfterSeconds + " 秒");
|
log.info("服务器要求等待 {} 秒", retryAfterSeconds);
|
||||||
Thread.sleep(retryAfterSeconds * 1000L);
|
Thread.sleep(retryAfterSeconds * 1000L);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
System.out.println("等待5秒后重试");
|
log.info("等待5秒后重试");
|
||||||
Thread.sleep(5000);
|
Thread.sleep(5000);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
System.out.println("等待3秒后重试");
|
log.info("等待3秒后重试");
|
||||||
Thread.sleep(3000);
|
Thread.sleep(3000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user