diff --git a/mywust-core/pom.xml b/mywust-core/pom.xml index d554722..152ba96 100644 --- a/mywust-core/pom.xml +++ b/mywust-core/pom.xml @@ -23,6 +23,12 @@ 0.0.1-dev + + org.slf4j + slf4j-api + 1.7.36 + + net.sourceforge.jregex jregex diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/api/Bkjx.java b/mywust-core/src/main/java/cn/linghang/mywust/core/api/Bkjx.java new file mode 100644 index 0000000..384129e --- /dev/null +++ b/mywust-core/src/main/java/cn/linghang/mywust/core/api/Bkjx.java @@ -0,0 +1,21 @@ +package cn.linghang.mywust.core.api; + +import lombok.Getter; + +/** + *

Bkjx(本科教学)系统对应的API常量列表(拼音咱就别吐槽了吧...)

+ *

其实是本科生用的教务处系统

+ */ +@Getter +public class Bkjx { + public static final String BKJX_SSO_SERVICE = "http://bkjx.wust.edu.cn/jsxsd/sso.jsp"; + public static final String BKJX_SESSION_COOKIE_API = "http://bkjx.wust.edu.cn/jsxsd/sso.jsp?ticket=%s"; + + public static final String BKJX_TEST_API = "http://bkjx.wust.edu.cn/jsxsd/xxwcqk/xxwcqk_idxOnzh.do"; + + public static class Legacy { + public static final String BKJX_INDEX = "http://bkjx.wust.edu.cn"; + public static final String BKJX_DATA_STRING_API = "http://bkjx.wust.edu.cn/Logon.do?method=logon&flag=sess"; + public static final String BKJX_SESSION_COOKIE_API = "http://bkjx.wust.edu.cn/Logon.do?method=logon"; + } +} diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/api/JwcApiUrl.java b/mywust-core/src/main/java/cn/linghang/mywust/core/api/JwcApiUrl.java deleted file mode 100644 index 68b25e9..0000000 --- a/mywust-core/src/main/java/cn/linghang/mywust/core/api/JwcApiUrl.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.linghang.mywust.core.api; - -import lombok.Getter; - -@Getter -public class JwcApiUrl { - /** - * 统一认证登录验证的api地址,请求之后可进一步获取ticket - */ - public static final String UNION_AUTH_API = "https://auth.wust.edu.cn/lyuapServer/v1/tickets"; - - public static final String JWC_SSO_SERVICE = "http://bkjx.wust.edu.cn/jsxsd/sso.jsp"; - public static final String JWC_TICKET_API = "http://bkjx.wust.edu.cn/jsxsd/sso.jsp?ticket=%s"; - -} diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/api/UnionAuth.java b/mywust-core/src/main/java/cn/linghang/mywust/core/api/UnionAuth.java new file mode 100644 index 0000000..f6778dd --- /dev/null +++ b/mywust-core/src/main/java/cn/linghang/mywust/core/api/UnionAuth.java @@ -0,0 +1,8 @@ +package cn.linghang.mywust.core.api; + +public class UnionAuth { + /** + * 统一认证登录验证的api地址,请求之后可进一步获取service ticket来对具体的服务进行登录获取Cookies + */ + public static final String UNION_AUTH_API = "https://auth.wust.edu.cn/lyuapServer/v1/tickets"; +} diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/UnionLogin.java b/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/UnionLogin.java new file mode 100644 index 0000000..2749917 --- /dev/null +++ b/mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/UnionLogin.java @@ -0,0 +1,58 @@ +package cn.linghang.mywust.core.service.auth; + +import cn.linghang.mywust.core.api.UnionAuth; +import cn.linghang.mywust.core.exception.BasicException; +import cn.linghang.mywust.core.exception.PasswordWornException; +import cn.linghang.mywust.core.service.undergraduate.AuthRequestFactory; +import cn.linghang.mywust.network.HttpRequest; +import cn.linghang.mywust.network.HttpResponse; +import cn.linghang.mywust.network.RequestClientOption; +import cn.linghang.mywust.network.Requester; +import cn.linghang.mywust.util.PasswordEncoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URL; + +/** + * 统一认证登录 + */ +public class UnionLogin { + Logger log = LoggerFactory.getLogger(UnionLogin.class); + + private final Requester requester; + + public UnionLogin(Requester requester) { + this.requester = requester; + } + + public String getServiceTicket(String username, String password, String serviceUrl, RequestClientOption requestOption) throws IOException, BasicException { + String encodedPassword = PasswordEncoder.encodePassword(password); + + // 获取ticket granting ticket(TGT),以获取ServiceTicket + HttpRequest TGTRequest = AuthRequestFactory.unionLoginTGTRequest(username, encodedPassword, serviceUrl); + + HttpResponse unionAuthResponse = requester.post(new URL(UnionAuth.UNION_AUTH_API), TGTRequest, requestOption); + + String redirectAddress = unionAuthResponse.getHeaders().get("Location"); + if (redirectAddress == null) { + throw new PasswordWornException(); + } + + // 获取服务ticket(service ticket,ST) + HttpRequest serviceTicketRequest = AuthRequestFactory.loginTicketRequest(serviceUrl); + + HttpResponse serviceTicketResponse = + requester.post(new URL(redirectAddress.replace("http:", "https:")), serviceTicketRequest, requestOption); + + byte[] serviceTicketResponseData = serviceTicketResponse.getBody(); + if (serviceTicketResponseData == null) { + log.warn("获取服务st出错,serviceTicketResponseData == null"); + + throw new BasicException(); + } + + return new String(serviceTicketResponseData); + } +} diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/AuthRequestFactory.java b/mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/AuthRequestFactory.java new file mode 100644 index 0000000..f69d909 --- /dev/null +++ b/mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/AuthRequestFactory.java @@ -0,0 +1,68 @@ +package cn.linghang.mywust.core.service.undergraduate; + +import cn.linghang.mywust.network.HttpRequest; +import cn.linghang.mywust.util.StringUtil; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +public class AuthRequestFactory { + public static HttpRequest unionLoginTGTRequest(String username, String password, String service) { + Map requestForm = new HashMap<>(4); + requestForm.put("username", username); + requestForm.put("password", password); + requestForm.put("service", service); + requestForm.put("loginType", ""); + + String queryString = StringUtil.generateQueryString(requestForm); + + HttpRequest request = new HttpRequest(); + request.setData(queryString.getBytes(StandardCharsets.UTF_8)); + + return request; + } + + public static HttpRequest loginTicketRequest(String service) { + Map requestForm = new HashMap<>(1); + requestForm.put("service", service); + + String queryString = StringUtil.generateQueryString(requestForm); + + HttpRequest request = new HttpRequest(); + request.setData(queryString.getBytes(StandardCharsets.UTF_8)); + + return request; + } + + public static HttpRequest sessionCookieRequest() { + return DEFAULT_HTTP_REQUEST; + } + + private static final HttpRequest DEFAULT_HTTP_REQUEST = new HttpRequest(); + + public static class Legacy { + public static HttpRequest dataStringRequest() { + return DEFAULT_HTTP_REQUEST; + } + + public static HttpRequest ticketRedirectRequest(String encode) { + Map queryParams = new HashMap<>(); + queryParams.put("userAccount", ""); + queryParams.put("userPassword", ""); + queryParams.put("encoded", encode); + + String queryString = StringUtil.generateQueryString(queryParams); + + Map extendHeaders = new HashMap<>(); + extendHeaders.put("Referer", "http://bkjx.wust.edu.cn/"); + extendHeaders.put("Origin", "http://bkjx.wust.edu.cn"); + + HttpRequest httpRequest = new HttpRequest(); + httpRequest.setHeaders(extendHeaders); + httpRequest.setData(queryString.getBytes(StandardCharsets.UTF_8)); + + return httpRequest; + } + } +} diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/AuthRequestGenerator.java b/mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/AuthRequestGenerator.java deleted file mode 100644 index eeb2dc9..0000000 --- a/mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/AuthRequestGenerator.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.linghang.mywust.core.service.undergraduate; - -import cn.linghang.mywust.network.HttpRequest; -import cn.linghang.mywust.util.StringUtil; - -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; - -public class AuthRequestGenerator { - public static HttpRequest unionLoginTGTRequest(String username, String password, String service) { - Map requestForm = new HashMap<>(); - requestForm.put("username", username); - requestForm.put("password", password); - requestForm.put("service", service); - requestForm.put("loginType", ""); - - String queryString = StringUtil.generateQueryString(requestForm); - - HttpRequest request = new HttpRequest(); - request.setData(queryString.getBytes(StandardCharsets.UTF_8)); - - return request; - } - - public static HttpRequest loginTicketRequest(String service) { - Map requestForm = new HashMap<>(); - requestForm.put("service", service); - - String queryString = StringUtil.generateQueryString(requestForm); - - HttpRequest request = new HttpRequest(); - request.setData(queryString.getBytes(StandardCharsets.UTF_8)); - - return request; - } - - public static HttpRequest sessionCookieRequest() { - return new HttpRequest(); - } -} diff --git a/mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/JwcLogin.java b/mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/JwcLogin.java index 34e9f20..97f4482 100644 --- a/mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/JwcLogin.java +++ b/mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/JwcLogin.java @@ -1,65 +1,113 @@ package cn.linghang.mywust.core.service.undergraduate; -import cn.linghang.mywust.core.api.JwcApiUrl; +import cn.linghang.mywust.core.api.Bkjx; import cn.linghang.mywust.core.exception.BasicException; import cn.linghang.mywust.core.exception.PasswordWornException; +import cn.linghang.mywust.core.service.auth.UnionLogin; import cn.linghang.mywust.network.HttpRequest; import cn.linghang.mywust.network.HttpResponse; import cn.linghang.mywust.network.RequestClientOption; import cn.linghang.mywust.network.Requester; +import cn.linghang.mywust.util.PasswordEncoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URL; public class JwcLogin { - // 默认5秒超时 - private static final int DEFAULT_TIMEOUT = 5; + private static final Logger log = LoggerFactory.getLogger(JwcLogin.class); private final Requester requester; - public JwcLogin(Requester requester) { + private final UnionLogin unionLogin; + + public JwcLogin(Requester requester, UnionLogin unionLogin) { this.requester = requester; + this.unionLogin = unionLogin; } - public String getLoginCookie(String username, String password, RequestClientOption requestOption) throws IOException, BasicException { - // 获取ticket granting ticket(TGT) - HttpRequest TGTRequest = AuthRequestGenerator.unionLoginTGTRequest(username, password, JwcApiUrl.JWC_SSO_SERVICE); + /** + *

旧版的登录方式,既相当于直接登录bkjx系统

+ *

注意,这种登录方式的密码和新版可能是不一样的

+ *

不过不论使用哪种登录方式获取到的cookie都是可用的

+ * + * @return 获取到的Cookies + */ + public String getLoginCookieLegacy(String username, String password, RequestClientOption requestOption) throws IOException, BasicException { + // 获取某段神秘的dataStr(反正官网代码是这么叫的) + HttpRequest dataStringRequest = AuthRequestFactory.Legacy.dataStringRequest(); + HttpResponse dataStringResponse = requester.post(new URL(Bkjx.Legacy.BKJX_DATA_STRING_API), dataStringRequest, requestOption); + if (dataStringResponse.getBody() == null) { + throw new BasicException(); + } - HttpResponse unionAuthResponse = requester.post(new URL(JwcApiUrl.UNION_AUTH_API), TGTRequest, requestOption); + String dataString = new String(dataStringResponse.getBody()); - String redirectAddress = unionAuthResponse.getHeaders().get("Location"); - if (redirectAddress == null) { - throw new PasswordWornException(); + // 获取登录ticket + String encoded = PasswordEncoder.legacyPassword(username, password, dataString); + HttpRequest ticketRequest = AuthRequestFactory.Legacy.ticketRedirectRequest(encoded); + ticketRequest.setCookies(dataStringResponse.getCookies()); + HttpResponse ticketResponse = requester.post(new URL(Bkjx.Legacy.BKJX_SESSION_COOKIE_API), ticketRequest, requestOption); + if (ticketResponse.getBody() == null) { + throw new BasicException(); } - // 获取服务ticket(service ticket,st) - HttpRequest serviceTicketRequest = AuthRequestGenerator.loginTicketRequest(JwcApiUrl.JWC_SSO_SERVICE); + // 使用跳转得到的链接获取cookies + String sessionRedirect = ticketResponse.getHeaders().get("Location"); + if (sessionRedirect == null) { + throw new PasswordWornException(); + } + HttpRequest sessionRequest = AuthRequestFactory.Legacy.dataStringRequest(); - HttpResponse serviceTicketResponse = - requester.post(new URL(redirectAddress.replace("http:", "https:")), serviceTicketRequest, requestOption); + HttpResponse sessionResponse = requester.get(new URL(sessionRedirect), sessionRequest, requestOption); - byte[] serviceTicketResponseData = serviceTicketResponse.getBody(); - if (serviceTicketResponseData == null) { - System.err.println("获取服务st出错,serviceTicketResponseData == null"); + String cookies = sessionResponse.getCookies(); + if (roughCheckCookie(cookies)) { throw new BasicException(); } - String serviceTicket = new String(serviceTicketResponseData); + + return cookies; + } + + public String getLoginCookie(String username, String password, RequestClientOption requestOption) throws IOException, BasicException { + String serviceTicket = unionLogin.getServiceTicket(username, password, Bkjx.BKJX_SSO_SERVICE, requestOption); // 获取登录cookie(session) - HttpRequest sessionRequest = AuthRequestGenerator.sessionCookieRequest(); - HttpResponse sessionResponse = requester.get(new URL(String.format(JwcApiUrl.JWC_TICKET_API, serviceTicket)), sessionRequest, requestOption); + HttpRequest sessionRequest = AuthRequestFactory.sessionCookieRequest(); + HttpResponse sessionResponse = requester.get(new URL(String.format(Bkjx.BKJX_SESSION_COOKIE_API, serviceTicket)), sessionRequest, requestOption); String cookies = sessionResponse.getCookies(); - if (cookies == null || !cookies.contains("JSESSIONID") || !cookies.contains("SERVERID")) { - System.err.println("获取服务session cookie出错,关键Cookie缺失"); - System.err.println("Cookies: " + cookies); + if (roughCheckCookie(cookies)) { throw new BasicException(); } return cookies; } - private void getLoginGTG(String username, String password) { + private boolean roughCheckCookie(String cookies) throws BasicException { + return cookies == null || !cookies.contains("JSESSIONID") || !cookies.contains("SERVERID"); + } + + private static final int COOKIES_ERROR_RESPONSE_LENGTH = + ("").length(); + + + public boolean checkCookies(String cookies) throws IOException { + RequestClientOption option = new RequestClientOption(); + option.setTimeout(5); + option.setProxy(null); + option.setFallowUrlRedirect(false); + HttpRequest testRequest = AuthRequestFactory.sessionCookieRequest(); + testRequest.setCookies(cookies); + HttpResponse testResponse = requester.get(new URL(Bkjx.BKJX_TEST_API), testRequest, option); + + // 判断响应长度是否为178个字,登录跳转响应长度 + // 这种办法虽然在极端情况下可能会出错(而且还挺蠢的),但是是最快的办法中比较准确的了 + return testResponse.getBody().length != COOKIES_ERROR_RESPONSE_LENGTH; } + } diff --git a/mywust-network-okhttp/pom.xml b/mywust-network-okhttp/pom.xml index 0791490..a7459bc 100644 --- a/mywust-network-okhttp/pom.xml +++ b/mywust-network-okhttp/pom.xml @@ -43,6 +43,12 @@ 2.13.4
+ + org.slf4j + slf4j-api + 1.7.36 + + cn.linghang mywust-network diff --git a/mywust-network-okhttp/src/main/java/cn/linghang/mywust/network/okhttp/RedirectInterceptor.java b/mywust-network-okhttp/src/main/java/cn/linghang/mywust/network/okhttp/RedirectInterceptor.java new file mode 100644 index 0000000..495b7c7 --- /dev/null +++ b/mywust-network-okhttp/src/main/java/cn/linghang/mywust/network/okhttp/RedirectInterceptor.java @@ -0,0 +1,22 @@ +package cn.linghang.mywust.network.okhttp; + +import okhttp3.Interceptor; +import okhttp3.Response; + +import java.io.IOException; + +public class RedirectInterceptor implements Interceptor { + + @Override + public Response intercept(Chain chain) throws IOException { + okhttp3.Request request = chain.request(); + Response response = chain.proceed(request); + + String location = response.headers().get("Location"); + if (location != null) { + System.out.println(("Request redirected to:" + location)); + } + + return response; + } +} \ No newline at end of file diff --git a/mywust-network-okhttp/src/main/java/cn/linghang/mywust/network/okhttp/SimpleOkhttpRequester.java b/mywust-network-okhttp/src/main/java/cn/linghang/mywust/network/okhttp/SimpleOkhttpRequester.java index cc52cae..e5f14b2 100644 --- a/mywust-network-okhttp/src/main/java/cn/linghang/mywust/network/okhttp/SimpleOkhttpRequester.java +++ b/mywust-network-okhttp/src/main/java/cn/linghang/mywust/network/okhttp/SimpleOkhttpRequester.java @@ -7,13 +7,14 @@ import cn.linghang.mywust.network.Requester; import cn.linghang.mywust.util.StringUtil; import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -36,6 +37,8 @@ import java.util.concurrent.TimeUnit; * @edit 2022-10-19 21:30 */ public class SimpleOkhttpRequester implements Requester { + private static final Logger log = LoggerFactory.getLogger(SimpleOkhttpRequester.class); + private final boolean useSingletonClient; private static volatile OkHttpClient rootClient; @@ -108,6 +111,8 @@ public class SimpleOkhttpRequester implements Requester { builder.callTimeout(requestClientOption.getTimeout(), TimeUnit.SECONDS) .readTimeout(requestClientOption.getTimeout(), TimeUnit.SECONDS) .connectTimeout(requestClientOption.getTimeout(), TimeUnit.SECONDS) + .followRedirects(requestClientOption.isFallowUrlRedirect()) + .addInterceptor(new RedirectInterceptor()) .sslSocketFactory(TrustAllCert.getSSLSocketFactory(), TrustAllCert.getX509TrustManager()) .hostnameVerifier(TrustAllCert.getHostnameVerifier()); @@ -169,10 +174,10 @@ public class SimpleOkhttpRequester implements Requester { } String contentType = headers.get("Content-Type"); - if (!"".equals(contentType)) { - return MediaType.get(contentType); - } else { + if (contentType == null || "".equals(contentType)) { return MediaType.get(DEFAULT_CONTENT_TYPE); + } else { + return MediaType.get(contentType); } } @@ -197,18 +202,23 @@ public class SimpleOkhttpRequester implements Requester { requestBuilder.header("Cookie", requestCookie); } + byte[] data = httpRequest.getData(); + if (data == null && requestMethod != RequestMethod.GET) { + data = new byte[]{0}; + } + if (requestMethod == RequestMethod.GET) { requestBuilder.get(); } else if (requestMethod == RequestMethod.POST) { - requestBuilder.post(RequestBody.create(this.getMediaType(httpRequest), httpRequest.getData())); + requestBuilder.post(RequestBody.create(this.getMediaType(httpRequest), data)); } else if (requestMethod == RequestMethod.PUT) { - requestBuilder.put(RequestBody.create(this.getMediaType(httpRequest), httpRequest.getData())); + requestBuilder.put(RequestBody.create(this.getMediaType(httpRequest), data)); } else if (requestMethod == RequestMethod.DELETE) { if (httpRequest.getData() != null) { - requestBuilder.delete(RequestBody.create(this.getMediaType(httpRequest), httpRequest.getData())); + requestBuilder.delete(RequestBody.create(this.getMediaType(httpRequest), data)); } else { requestBuilder.delete(); } diff --git a/mywust-network/src/main/java/cn/linghang/mywust/network/HttpRequest.java b/mywust-network/src/main/java/cn/linghang/mywust/network/HttpRequest.java index 6855f07..ac68688 100644 --- a/mywust-network/src/main/java/cn/linghang/mywust/network/HttpRequest.java +++ b/mywust-network/src/main/java/cn/linghang/mywust/network/HttpRequest.java @@ -2,10 +2,24 @@ package cn.linghang.mywust.network; import lombok.Data; +import java.util.HashMap; import java.util.Map; @Data public class HttpRequest { + private static final Map DEFAULT_HEADERS = initDefaultHeaders(); + + private static Map initDefaultHeaders() { + Map defaultHeaders = new HashMap<>(); + defaultHeaders.put("Accept", "application/json, text/plain, */*"); + defaultHeaders.put("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"); + defaultHeaders.put("Cache-Control", "no-cache"); + defaultHeaders.put("Connection", "keep-alive"); + defaultHeaders.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.47"); + + return defaultHeaders; + } + private Map urlParams; private Map headers; @@ -13,4 +27,27 @@ public class HttpRequest { private String cookies; private byte[] data; + + public HttpRequest() { + headers = new HashMap<>(DEFAULT_HEADERS); + } + + public void setHeaders(Map headers) { + this.headers.putAll(headers); + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("HttpRequest{"); + sb.append("urlParams=").append(urlParams); + sb.append(", headers=").append(headers); + sb.append(", cookies='").append(cookies).append('\''); + sb.append(", data="); + if (data == null) sb.append("null"); + else { + sb.append(new String(data)); + } + sb.append('}'); + return sb.toString(); + } } diff --git a/mywust-network/src/main/java/cn/linghang/mywust/network/HttpResponse.java b/mywust-network/src/main/java/cn/linghang/mywust/network/HttpResponse.java index ee67eb4..cd59ecb 100644 --- a/mywust-network/src/main/java/cn/linghang/mywust/network/HttpResponse.java +++ b/mywust-network/src/main/java/cn/linghang/mywust/network/HttpResponse.java @@ -2,7 +2,6 @@ package cn.linghang.mywust.network; import lombok.Data; -import java.util.List; import java.util.Map; @Data @@ -12,4 +11,18 @@ public class HttpResponse { private String cookies; private byte[] body; + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("HttpResponse{"); + sb.append("headers=").append(headers); + sb.append(", cookies='").append(cookies).append('\''); + sb.append(", body="); + if (body == null) sb.append("null"); + else { + sb.append(new String(body)); + } + sb.append('}'); + return sb.toString(); + } } diff --git a/mywust-test/src/test/java/JwcLegacyLoginTest.java b/mywust-test/src/test/java/JwcLegacyLoginTest.java new file mode 100644 index 0000000..ddf3af6 --- /dev/null +++ b/mywust-test/src/test/java/JwcLegacyLoginTest.java @@ -0,0 +1,41 @@ +import cn.linghang.mywust.core.exception.BasicException; +import cn.linghang.mywust.core.service.auth.UnionLogin; +import cn.linghang.mywust.core.service.undergraduate.JwcLogin; +import cn.linghang.mywust.network.RequestClientOption; +import cn.linghang.mywust.network.Requester; +import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester; + +import java.io.IOException; +import java.util.Scanner; + +public class JwcLegacyLoginTest { + public static void main(String[] args) throws BasicException, IOException { + new JwcLegacyLoginTest().run(); + } + + private void run() throws BasicException, IOException { + System.out.println("输入账号(学号)和密码,用“ ”(空格)分割"); + + Scanner scanner = new Scanner(System.in); + + String input = scanner.nextLine(); + + String username = input.split(" ")[0]; + String password = input.split(" ")[1]; + + System.out.println("账号:" + username); + System.out.println("密码:" + password); + + Requester requester = new SimpleOkhttpRequester(); + JwcLogin jwcLogin = new JwcLogin(requester, new UnionLogin(requester)); + + RequestClientOption option = new RequestClientOption(); + option.setTimeout(5); + option.setProxy(null); + option.setFallowUrlRedirect(false); + + String cookies = jwcLogin.getLoginCookieLegacy(username, password, option); + + System.out.println(cookies); + } +} diff --git a/mywust-test/src/test/java/JwcLoginTest.java b/mywust-test/src/test/java/JwcLoginTest.java index 8d42323..552ff17 100644 --- a/mywust-test/src/test/java/JwcLoginTest.java +++ b/mywust-test/src/test/java/JwcLoginTest.java @@ -1,8 +1,9 @@ import cn.linghang.mywust.core.exception.BasicException; +import cn.linghang.mywust.core.service.auth.UnionLogin; import cn.linghang.mywust.core.service.undergraduate.JwcLogin; import cn.linghang.mywust.network.RequestClientOption; +import cn.linghang.mywust.network.Requester; import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester; -import cn.linghang.mywust.util.PasswordEncoder; import java.io.IOException; import java.util.Scanner; @@ -25,14 +26,15 @@ public class JwcLoginTest { System.out.println("账号:" + username); System.out.println("密码:" + password); - JwcLogin jwcLogin = new JwcLogin(new SimpleOkhttpRequester()); + Requester requester = new SimpleOkhttpRequester(); + JwcLogin jwcLogin = new JwcLogin(requester, new UnionLogin(requester)); RequestClientOption option = new RequestClientOption(); option.setTimeout(5); option.setProxy(null); option.setFallowUrlRedirect(false); - String cookies = jwcLogin.getLoginCookie(username, PasswordEncoder.encodePassword(password), option); + String cookies = jwcLogin.getLoginCookie(username, password, option); System.out.println(cookies); } diff --git a/mywust-util/src/main/java/cn/linghang/mywust/util/PasswordEncoder.java b/mywust-util/src/main/java/cn/linghang/mywust/util/PasswordEncoder.java index c1bd3b1..3c4fe7e 100644 --- a/mywust-util/src/main/java/cn/linghang/mywust/util/PasswordEncoder.java +++ b/mywust-util/src/main/java/cn/linghang/mywust/util/PasswordEncoder.java @@ -16,6 +16,8 @@ import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAPublicKeySpec; +import static java.lang.Integer.parseInt; + /** * 密码加密工具类 * @@ -27,6 +29,7 @@ import java.security.spec.RSAPublicKeySpec; *

- 将生成的字节数组转换成16进制字符串,得到加密后的数据

*
*

希望不要再改登录方式了 [拜]

+ * * @author : lensfrex * @description : 使用统一登陆的加密方法对密码进行加密的工具类 * @create : 2022-09-18 14:42:06 @@ -69,7 +72,7 @@ public class PasswordEncoder { // 完成加密 return Hex.encodeHexString(cipher.doFinal(reversedTextData)); - } catch (IllegalBlockSizeException | BadPaddingException e) { + } catch (IllegalBlockSizeException | BadPaddingException e) { // 会报错的地方都是因为算法不正确,这里都是固定的值,出错了就是程序写错了,在测试的时候就应该发现的问题 // 对于调用者不必处理这种异常,但是开发测试的时候应该要打日志来发现问题 System.err.println("加密出错"); @@ -101,4 +104,34 @@ public class PasswordEncoder { return null; } + + /** + *

使用旧版登录页的方法加密密码(bkjx系统直接登录)

+ *

是直接照搬官网js代码的,只是经过了一点小修改,没有具体研究是什么加密方式(大概率可能是自创的),性能可能会有点差

+ * + * @param dataString 加密前置字符串 + * @param password 密码明文 + * @return 加密后的密文 + */ + public static String legacyPassword(String username, String password, String dataString) { + String[] parts = dataString.split("#"); + String scode = parts[0]; + String sxh = parts[1]; + + String code = username + "%%%" + password; + + StringBuilder encoded = new StringBuilder(); + for (int i = 0, codeLength = code.length(); i < codeLength; i++) { + if (i < 20) { + int endIndex = parseInt(sxh.substring(i, i + 1)); + encoded.append(code.charAt(i)).append(scode, 0, endIndex); + scode = scode.substring(endIndex); + } else { + encoded.append(code.substring(i)); + i = codeLength; + } + } + + return encoded.toString(); + } } diff --git a/mywust-util/src/main/java/cn/linghang/mywust/util/StringUtil.java b/mywust-util/src/main/java/cn/linghang/mywust/util/StringUtil.java index 63af593..e260a24 100644 --- a/mywust-util/src/main/java/cn/linghang/mywust/util/StringUtil.java +++ b/mywust-util/src/main/java/cn/linghang/mywust/util/StringUtil.java @@ -27,11 +27,15 @@ public class StringUtil { * @return 解析后可用的Cookie */ public static String parseCookie(List cookieHeaders) { + if (cookieHeaders == null || cookieHeaders.isEmpty()) { + return null; + } + List allCookies = new ArrayList<>(cookieHeaders.size()); cookieHeaders.forEach((cookieHeader) -> allCookies.add(cookieHeader.split(";")[0])); return Joiner.on(';') - .useForNull("") + .skipNulls() .join(allCookies); } }