parent
f3aa0d4be0
commit
036c4b47be
@ -0,0 +1,95 @@ |
||||
package cn.linghang.mywust.core.service.auth; |
||||
|
||||
import cn.linghang.mywust.captcha.SolvedImageCaptcha; |
||||
import cn.linghang.mywust.captcha.UnsolvedImageCaptcha; |
||||
import cn.linghang.mywust.core.exception.ApiException; |
||||
import cn.linghang.mywust.core.exception.BasicException; |
||||
import cn.linghang.mywust.core.request.graduate.GraduateRequestFactory; |
||||
import cn.linghang.mywust.core.service.captcha.solver.CaptchaSolver; |
||||
import cn.linghang.mywust.network.RequestClientOption; |
||||
import cn.linghang.mywust.network.Requester; |
||||
import cn.linghang.mywust.network.entitys.HttpRequest; |
||||
import cn.linghang.mywust.network.entitys.HttpResponse; |
||||
|
||||
import javax.imageio.ImageIO; |
||||
import java.awt.*; |
||||
import java.awt.image.BufferedImage; |
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
|
||||
public class GraduateLogin { |
||||
private final Requester requester; |
||||
|
||||
private final CaptchaSolver captchaSolver; |
||||
|
||||
public GraduateLogin(Requester requester, CaptchaSolver captchaSolver) { |
||||
this.requester = requester; |
||||
this.captchaSolver = captchaSolver; |
||||
} |
||||
|
||||
public String getLoginCookie(String username, String password, RequestClientOption option) throws IOException, BasicException { |
||||
// 请求获取验证码
|
||||
HttpRequest captchaImageRequest = GraduateRequestFactory.captchaRequest(); |
||||
HttpResponse captchaImageResponse = requester.get(captchaImageRequest, option); |
||||
|
||||
UnsolvedImageCaptcha unsolvedImageCaptcha = new UnsolvedImageCaptcha(); |
||||
unsolvedImageCaptcha.setBindInfo(captchaImageResponse.getCookies()); |
||||
|
||||
byte[] processedImage = ImageUtil.process(captchaImageResponse.getBody()); |
||||
unsolvedImageCaptcha.setImage(processedImage); |
||||
|
||||
// 通过传入的captchaSolver来处理验证码
|
||||
SolvedImageCaptcha solvedImageCaptcha = captchaSolver.solve(unsolvedImageCaptcha); |
||||
|
||||
// 进行登录
|
||||
HttpRequest loginRequest = GraduateRequestFactory.loginRequest(username, password, solvedImageCaptcha); |
||||
HttpResponse loginResponse = requester.post(loginRequest, option); |
||||
|
||||
// 登陆成功,应该会是302跳转,不是的话多半是认证错误
|
||||
if (loginResponse.getStatusCode() != HttpResponse.HTTP_REDIRECT_302) { |
||||
throw new ApiException(ApiException.Code.GRADUATE_PASSWORD_WRONG); |
||||
} |
||||
|
||||
// 使用当初通过验证码得到的cookie来作为登录cookie,至于是否真正可行待验证
|
||||
return captchaImageResponse.getCookies(); |
||||
} |
||||
} |
||||
|
||||
class ImageUtil { |
||||
// 验证码图片的长宽
|
||||
private static final int IMAGE_WIDTH = 75; |
||||
private static final int IMAGE_HEIGHT = 35; |
||||
|
||||
// 二值化阈值,实测339效果最佳
|
||||
private static final int LIMIT = 339; |
||||
|
||||
private static final int BLACK = Color.BLACK.getRGB(); |
||||
private static final int WHITE = Color.WHITE.getRGB(); |
||||
|
||||
/** |
||||
* 初步处理验证码图片,对图片去色处理以更好地进行ocr处理 |
||||
*/ |
||||
public static byte[] process(byte[] data) throws ApiException { |
||||
try { |
||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data); |
||||
BufferedImage bufferedImage = ImageIO.read(byteArrayInputStream); |
||||
|
||||
for (int i = 0; i < IMAGE_WIDTH; ++i) { |
||||
for (int j = 0; j < IMAGE_HEIGHT; ++j) { |
||||
int rgb = bufferedImage.getRGB(i, j); |
||||
int bright = ((rgb >> 16) & 0xff) + ((rgb >> 8) & 0xff) + (rgb & 0xff); |
||||
|
||||
bufferedImage.setRGB(i, j, bright <= LIMIT ? BLACK : WHITE); |
||||
} |
||||
} |
||||
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
||||
ImageIO.write(bufferedImage, "png", outputStream); |
||||
|
||||
return byteArrayInputStream.readAllBytes(); |
||||
} catch (Exception e) { |
||||
throw new ApiException(ApiException.Code.INTERNAL_EXCEPTION); |
||||
} |
||||
} |
||||
} |
@ -1,8 +1,9 @@ |
||||
package cn.linghang.mywust.captcha.solver; |
||||
package cn.linghang.mywust.core.service.captcha.solver; |
||||
|
||||
import cn.linghang.mywust.captcha.SolvedImageCaptcha; |
||||
import cn.linghang.mywust.captcha.UnsolvedImageCaptcha; |
||||
import cn.linghang.mywust.core.exception.ApiException; |
||||
|
||||
public interface CaptchaSolver { |
||||
SolvedImageCaptcha solve(UnsolvedImageCaptcha unsolvedImageCaptcha); |
||||
SolvedImageCaptcha solve(UnsolvedImageCaptcha unsolvedImageCaptcha) throws ApiException; |
||||
} |
@ -0,0 +1,77 @@ |
||||
package cn.linghang.mywust.core.service.captcha.solver; |
||||
|
||||
import cn.linghang.mywust.captcha.SolvedImageCaptcha; |
||||
import cn.linghang.mywust.captcha.UnsolvedImageCaptcha; |
||||
import cn.linghang.mywust.core.exception.ApiException; |
||||
import cn.linghang.mywust.core.request.RequestFactory; |
||||
import cn.linghang.mywust.network.RequestClientOption; |
||||
import cn.linghang.mywust.network.Requester; |
||||
import cn.linghang.mywust.network.entitys.HttpRequest; |
||||
import cn.linghang.mywust.network.entitys.HttpResponse; |
||||
import cn.linghang.mywust.util.StringUtil; |
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
import org.apache.commons.codec.binary.Base64; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
import java.util.TreeMap; |
||||
|
||||
public class LinghangOcrServiceCaptchaSolver implements CaptchaSolver { |
||||
private final String baseUrl; |
||||
private final Requester requester; |
||||
|
||||
private final String appId; |
||||
private final String secretKey; |
||||
|
||||
private static final RequestClientOption requestOption = new RequestClientOption(); |
||||
|
||||
public LinghangOcrServiceCaptchaSolver(String baseUrl, Requester requester, |
||||
String appId, String secretKey) { |
||||
|
||||
this.baseUrl = baseUrl; |
||||
this.requester = requester; |
||||
|
||||
this.appId = appId; |
||||
this.secretKey = secretKey; |
||||
} |
||||
|
||||
@Override |
||||
public SolvedImageCaptcha solve(UnsolvedImageCaptcha unsolvedImageCaptcha) throws ApiException { |
||||
Map<String, String> urlParams = new TreeMap<>(String::compareTo); |
||||
urlParams.put("id", appId); |
||||
urlParams.put("t", Long.toString(System.currentTimeMillis() / 1000)); |
||||
urlParams.put("type", "json"); |
||||
|
||||
String sign = StringUtil.generateSignText(appId, secretKey, urlParams); |
||||
urlParams.put("sign", sign); |
||||
|
||||
String url = baseUrl + StringUtil.generateQueryString(urlParams); |
||||
byte[] imageBase64Data = Base64.encodeBase64(unsolvedImageCaptcha.getImage()); |
||||
|
||||
HttpRequest request; |
||||
HttpResponse response; |
||||
OcrResult result; |
||||
try { |
||||
request = RequestFactory.makeHttpRequest(url, imageBase64Data); |
||||
response = requester.post(request, requestOption); |
||||
result = new ObjectMapper().readValue(response.getBody(), OcrResult.class); |
||||
} catch (IOException e) { |
||||
throw new ApiException(ApiException.Code.NETWORK_EXCEPTION); |
||||
} |
||||
|
||||
if (result.code != OcrResult.CODE_SUCCESS) { |
||||
throw new ApiException(ApiException.Code.INTERNAL_EXCEPTION); |
||||
} |
||||
|
||||
return new SolvedImageCaptcha(unsolvedImageCaptcha, result.result); |
||||
} |
||||
|
||||
private static class OcrResult { |
||||
private int code; |
||||
private String result; |
||||
private String message; |
||||
|
||||
public static final int CODE_SUCCESS = 0; |
||||
} |
||||
|
||||
} |
@ -1,4 +1,4 @@ |
||||
package cn.linghang.mywust.captcha.solver; |
||||
package cn.linghang.mywust.core.service.captcha.solver; |
||||
|
||||
import cn.linghang.mywust.captcha.SolvedImageCaptcha; |
||||
import cn.linghang.mywust.captcha.UnsolvedImageCaptcha; |
@ -1,25 +1,37 @@ |
||||
package cn.linghang.mywust.captcha; |
||||
|
||||
import lombok.Data; |
||||
import lombok.Getter; |
||||
|
||||
/** |
||||
* 已处理的图片验证码 |
||||
* 已处理的图片验证码,必须要和特定的未处理验证码绑定 |
||||
*/ |
||||
@Data |
||||
@Getter |
||||
public class SolvedImageCaptcha { |
||||
/** |
||||
* 和验证码绑定的信息,如cookie,某种id等 |
||||
*/ |
||||
private String bindInfo; |
||||
private final String bindInfo; |
||||
|
||||
/** |
||||
* 验证码验证数据 |
||||
*/ |
||||
private String result; |
||||
|
||||
public SolvedImageCaptcha(String bindInfo) { |
||||
this.bindInfo = bindInfo; |
||||
} |
||||
|
||||
public SolvedImageCaptcha(UnsolvedImageCaptcha unsolvedImageCaptcha) { |
||||
this.bindInfo = unsolvedImageCaptcha.getBindInfo(); |
||||
this(unsolvedImageCaptcha.getBindInfo()); |
||||
} |
||||
|
||||
private void setBindInfo(String bindInfo) {} |
||||
public SolvedImageCaptcha(UnsolvedImageCaptcha unsolvedImageCaptcha, String result) { |
||||
this(unsolvedImageCaptcha); |
||||
this.result = result; |
||||
} |
||||
|
||||
public void setResult(String result) { |
||||
this.result = result; |
||||
} |
||||
} |
||||
|
@ -1,11 +0,0 @@ |
||||
package cn.linghang.mywust.captcha.solver; |
||||
|
||||
import cn.linghang.mywust.captcha.SolvedImageCaptcha; |
||||
import cn.linghang.mywust.captcha.UnsolvedImageCaptcha; |
||||
|
||||
public class LinghangOcrServiceCaptchaSolver implements CaptchaSolver { |
||||
@Override |
||||
public SolvedImageCaptcha solve(UnsolvedImageCaptcha unsolvedImageCaptcha) { |
||||
return null; |
||||
} |
||||
} |
Loading…
Reference in new issue