mirror of
https://github.com/czp3009/bilibili-api.git
synced 2025-02-19 20:50:28 +08:00
实现带验证码的登录
This commit is contained in:
parent
ef04b65984
commit
0219a0c8fe
62
README.md
62
README.md
@ -50,6 +50,8 @@ IOException 在网络故障时抛出
|
||||
|
||||
LoginException 在用户名密码不匹配时抛出
|
||||
|
||||
CaptchaMismatchException 在验证码不正确时抛出, 见下文 [验证码问题](#验证码问题) 一节
|
||||
|
||||
login 方法的返回值为 LoginResponseEntity 类型, 使用
|
||||
|
||||
.login(...).toBilibiliAccount()
|
||||
@ -79,6 +81,66 @@ IOException 在网络故障时抛出
|
||||
|
||||
LoginException 在 accessToken 错误或过期时抛出
|
||||
|
||||
### 验证码问题
|
||||
当对一个账户在短时间内(时长不明确)尝试多次错误的登录(密码错误)后, 再尝试登录该账号, 会被要求验证码.
|
||||
|
||||
此时登录操作会抛出 CaptchaMismatchException 异常, 表示必须调用另一个接口
|
||||
|
||||
public LoginResponseEntity login(String username,
|
||||
String password,
|
||||
String captcha,
|
||||
String cookie) throws IOException, LoginException, CaptchaMismatchException
|
||||
|
||||
这个接口将带 captcha 参数地去登录, 注意这里还有一个 cookie 参数.
|
||||
|
||||
下面先给出一段正确使用该接口的代码, 随后会解释其步骤
|
||||
|
||||
String username = "yourUsername";
|
||||
String password = "yourPassword";
|
||||
BilibiliAPI bilibiliAPI = new BilibiliAPI();
|
||||
try {
|
||||
bilibiliAPI.login(username, password);
|
||||
} catch (CaptchaMismatchException e) { //如果该账号现在需要验证码来进行登录, 就会抛出异常
|
||||
final cookie = "sid=123456"; //自己造一个 cookie 或者从服务器取得
|
||||
Response response = bilibiliAPI.getPassportService()
|
||||
.getCaptcha(cookie)
|
||||
.execute();
|
||||
InputStream inputStream = response.body().byteStream();
|
||||
String captcha = letUserInputCaptcha(inputStream); //让用户根据图片输入验证码
|
||||
bilibiliAPI.login(
|
||||
username,
|
||||
password,
|
||||
captcha,
|
||||
cookie
|
||||
);
|
||||
}
|
||||
|
||||
验证码是通过访问 https://passport.bilibili.com/captcha 这个地址获得的.
|
||||
|
||||
访问这个地址需要带有一个 cookie, cookie 里面要有 "sid=xxx", 然后服务端会记录下对应关系, 也就是 sid xxx 对应验证码 yyy, 然后就可以验证了.
|
||||
|
||||
我们会发现, 访问任何 passport.bilibili.com 下面的地址, 都会被分发一个 cookie, 里面带有 sid 的值. 我们访问 /captcha 也会被分发一个 cookie, 但是这个通过访问 captcha 而被分发得到的 cookie 和访问得到的验证码图片, 没有对应关系. 推测是因为 cookie 的发放在请求进入甚至模块运行完毕后才进行.
|
||||
|
||||
所以我们如果不带 cookie 去访问 /captcha, 我们这样拿到的由 /captcha 返回的 cookie 和 验证码, 是不匹配的.
|
||||
|
||||
所以我们要先从其他地方获取一个 cookie.
|
||||
|
||||
我们可以用 /api/oauth2/getKey(获取加密密码用的 hash 和公钥) 来获取一个 cookie
|
||||
|
||||
String cookie = bilibiliAPI.getPassportService()
|
||||
.getKey()
|
||||
.execute()
|
||||
.headers()
|
||||
.get("Set-cookie");
|
||||
|
||||
/captcha 不验证 cookie 正确性, 我们可以直接使用假的 cookie (比如 123456)对其发起验证码请求, 它会记录下这个假的 cookie 和 验证码 的对应关系, 一样能验证成功. 但是不推荐这么做.
|
||||
|
||||
简单地说, 只要我们是带 cookie 访问 /captcha 的, 那么我们得到的验证码, 是和这个 cookie 绑定的. 我们接下去用这个 cookie 和 这个验证码的值 去进行带验证码的登录, 就可以成功登陆.
|
||||
|
||||
至于验证码怎么处理, 可以显示给最终用户, 让用户来输入, 或者用一些预训练模型自动识别验证码.
|
||||
|
||||
这个带验证码的登录接口也会继续抛出 CaptchaMismatchException, 如果验证码输入错误的话.
|
||||
|
||||
### API 调用示例
|
||||
打印一个直播间的历史弹幕
|
||||
|
||||
|
@ -7,6 +7,7 @@ import com.hiczp.bilibili.api.passport.PassportService;
|
||||
import com.hiczp.bilibili.api.passport.entity.LoginResponseEntity;
|
||||
import com.hiczp.bilibili.api.passport.entity.LogoutResponseEntity;
|
||||
import com.hiczp.bilibili.api.passport.entity.RefreshTokenResponseEntity;
|
||||
import com.hiczp.bilibili.api.passport.exception.CaptchaMismatchException;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import org.slf4j.Logger;
|
||||
@ -20,7 +21,6 @@ import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
||||
//TODO 尚未实现自动 refreshToken 的拦截器
|
||||
public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BilibiliAPI.class);
|
||||
|
||||
@ -66,7 +66,7 @@ public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider
|
||||
))
|
||||
.addInterceptor(new AddAppKeyInterceptor(bilibiliClientProperties))
|
||||
.addInterceptor(new SortParamsAndSignInterceptor(bilibiliClientProperties))
|
||||
.addInterceptor(new ErrorResponseConverterInterceptor())
|
||||
.addInterceptor(new ErrorResponseBodyConverterInterceptor())
|
||||
.addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC))
|
||||
.build();
|
||||
|
||||
@ -107,7 +107,7 @@ public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider
|
||||
.addInterceptor(new AddAccessKeyInterceptor(bilibiliAccount))
|
||||
.addInterceptor(new AddAppKeyInterceptor(bilibiliClientProperties))
|
||||
.addInterceptor(new SortParamsAndSignInterceptor(bilibiliClientProperties))
|
||||
.addInterceptor(new ErrorResponseConverterInterceptor())
|
||||
.addInterceptor(new ErrorResponseBodyConverterInterceptor())
|
||||
.addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC))
|
||||
.build();
|
||||
|
||||
@ -121,12 +121,21 @@ public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider
|
||||
return liveService;
|
||||
}
|
||||
|
||||
public LoginResponseEntity login(String username, String password) throws IOException, LoginException {
|
||||
public LoginResponseEntity login(String username, String password) throws IOException, LoginException, CaptchaMismatchException {
|
||||
return login(username, password, null, null);
|
||||
}
|
||||
|
||||
public LoginResponseEntity login(String username,
|
||||
String password,
|
||||
String captcha,
|
||||
String cookie) throws IOException, LoginException, CaptchaMismatchException {
|
||||
LOGGER.info("Login attempting with username '{}'", username);
|
||||
LoginResponseEntity loginResponseEntity = BilibiliSecurityHelper.login(
|
||||
this,
|
||||
username,
|
||||
password
|
||||
password,
|
||||
captcha,
|
||||
cookie
|
||||
);
|
||||
//判断返回值
|
||||
switch (loginResponseEntity.getCode()) {
|
||||
@ -141,7 +150,7 @@ public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider
|
||||
throw new LoginException("password error or hash expired");
|
||||
}
|
||||
case ServerErrorCode.Passport.CAPTCHA_NOT_MATCH: {
|
||||
throw new LoginException(loginResponseEntity.getMessage());
|
||||
throw new CaptchaMismatchException(loginResponseEntity.getMessage());
|
||||
}
|
||||
default: {
|
||||
throw new IOException(loginResponseEntity.getMessage());
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.hiczp.bilibili.api;
|
||||
|
||||
import com.hiczp.bilibili.api.passport.PassportService;
|
||||
import com.hiczp.bilibili.api.passport.entity.KeyEntity;
|
||||
import com.hiczp.bilibili.api.passport.entity.LoginResponseEntity;
|
||||
import com.hiczp.bilibili.api.passport.entity.LogoutResponseEntity;
|
||||
@ -22,11 +21,9 @@ import java.util.Base64;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BilibiliSecurityHelper {
|
||||
public static LoginResponseEntity login(BilibiliServiceProvider bilibiliServiceProvider,
|
||||
String username,
|
||||
String password) throws IOException {
|
||||
PassportService passportService = bilibiliServiceProvider.getPassportService();
|
||||
KeyEntity keyEntity = passportService.getKey().execute().body();
|
||||
private static String cipherPassword(BilibiliServiceProvider bilibiliServiceProvider,
|
||||
String password) throws IOException {
|
||||
KeyEntity keyEntity = bilibiliServiceProvider.getPassportService().getKey().execute().body();
|
||||
//服务器返回异常错误码
|
||||
if (keyEntity.getCode() != 0) {
|
||||
throw new IOException(keyEntity.getMessage());
|
||||
@ -60,9 +57,27 @@ public class BilibiliSecurityHelper {
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new IOException("get broken RSA public key");
|
||||
}
|
||||
//发起登录请求
|
||||
return passportService.login(username, cipheredPassword)
|
||||
.execute()
|
||||
return cipheredPassword;
|
||||
}
|
||||
|
||||
public static LoginResponseEntity login(BilibiliServiceProvider bilibiliServiceProvider,
|
||||
String username,
|
||||
String password) throws IOException {
|
||||
return login(bilibiliServiceProvider, username, password, null, null);
|
||||
}
|
||||
|
||||
public static LoginResponseEntity login(BilibiliServiceProvider bilibiliServiceProvider,
|
||||
String username,
|
||||
String password,
|
||||
String captcha,
|
||||
String cookie) throws IOException {
|
||||
return bilibiliServiceProvider.getPassportService()
|
||||
.login(
|
||||
username,
|
||||
cipherPassword(bilibiliServiceProvider, password),
|
||||
captcha,
|
||||
cookie
|
||||
).execute()
|
||||
.body();
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@ import java.nio.charset.StandardCharsets;
|
||||
|
||||
//由于服务器返回错误时的 data 字段类型不固定, 会导致 json 反序列化出错.
|
||||
//该拦截器将在返回的 code 不为 0 时, 将 response 转换为包含一个空 data 的 json 字符串.
|
||||
public class ErrorResponseConverterInterceptor implements Interceptor {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ErrorResponseConverterInterceptor.class);
|
||||
public class ErrorResponseBodyConverterInterceptor implements Interceptor {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ErrorResponseBodyConverterInterceptor.class);
|
||||
private static final JsonParser JSON_PARSER = new JsonParser();
|
||||
private static final Gson GSON = new Gson();
|
||||
|
@ -0,0 +1,15 @@
|
||||
package com.hiczp.bilibili.api.interceptor;
|
||||
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
//当返回的数据中的 code 表示未登录时, 将 response 的 HttpStatus 改为 401, 以供 authenticator 使用
|
||||
//TODO 未实现
|
||||
public class ErrorResponseStatusConverterInterceptor implements Interceptor {
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@ -1,12 +1,30 @@
|
||||
package com.hiczp.bilibili.api.passport;
|
||||
|
||||
import com.hiczp.bilibili.api.BaseUrlDefinition;
|
||||
import com.hiczp.bilibili.api.passport.entity.*;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Header;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface PassportService {
|
||||
//获取验证码
|
||||
default okhttp3.Call getCaptcha(String cookies) {
|
||||
return new OkHttpClient.Builder()
|
||||
.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC))
|
||||
.build()
|
||||
.newCall(
|
||||
new Request.Builder()
|
||||
.url(BaseUrlDefinition.PASSPORT + "captcha")
|
||||
.header("Cookie", cookies)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@POST("api/oauth2/getKey")
|
||||
Call<KeyEntity> getKey();
|
||||
|
||||
@ -14,10 +32,8 @@ public interface PassportService {
|
||||
Call<LoginResponseEntity> login(@Query("username") String username, @Query("password") String password);
|
||||
|
||||
//在一段时间内进行多次错误的登录, 将被要求输入验证码
|
||||
//TODO 尚不明确 captcha 是如何工作的
|
||||
@Deprecated
|
||||
@POST("api/oauth2/login")
|
||||
Call<LoginResponseEntity> loginWithCaptcha(@Query("username") String username, @Query("password") String password, @Query("captcha") String captcha);
|
||||
Call<LoginResponseEntity> login(@Query("username") String username, @Query("password") String password, @Query("captcha") String captcha, @Header("Cookie") String cookies);
|
||||
|
||||
@GET("api/oauth2/info")
|
||||
Call<InfoEntity> getInfo(@Query("access_token") String accessToken);
|
||||
|
@ -0,0 +1,11 @@
|
||||
package com.hiczp.bilibili.api.passport.exception;
|
||||
|
||||
public class CaptchaMismatchException extends RuntimeException {
|
||||
public CaptchaMismatchException() {
|
||||
|
||||
}
|
||||
|
||||
public CaptchaMismatchException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.hiczp.bilibili.api.test.CaptchaInputDialog">
|
||||
<grid id="cbd77" binding="contentPane" layout-manager="GridBagLayout">
|
||||
<constraints>
|
||||
<xy x="48" y="54" width="436" height="297"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="empty">
|
||||
<size top="2" left="2" bottom="2" right="2"/>
|
||||
</border>
|
||||
<children>
|
||||
<grid id="94766" layout-manager="GridBagLayout">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
<gridbag weightx="1.0" weighty="0.0"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<preferredSize width="200" height="50"/>
|
||||
</properties>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="e7465" class="javax.swing.JButton" binding="buttonOK">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
<gridbag weightx="0.0" weighty="1.0"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="OK"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="9335c" class="javax.swing.JTextField" binding="textField">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
<gridbag weightx="1.0" weighty="1.0"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="e3588" layout-manager="GridBagLayout">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
<gridbag weightx="1.0" weighty="1.0"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<preferredSize width="200" height="50"/>
|
||||
</properties>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="85fac" class="javax.swing.JLabel" binding="label" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
<gridbag weightx="1.0" weighty="1.0"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Label"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
@ -0,0 +1,131 @@
|
||||
package com.hiczp.bilibili.api.test;
|
||||
|
||||
import com.hiczp.bilibili.api.BilibiliAPI;
|
||||
import okhttp3.Response;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CaptchaInputDialog extends JDialog {
|
||||
private String cookie;
|
||||
private String captcha;
|
||||
|
||||
private JPanel contentPane;
|
||||
private JButton buttonOK;
|
||||
private JTextField textField;
|
||||
private JLabel label;
|
||||
|
||||
public CaptchaInputDialog() {
|
||||
$$$setupUI$$$();
|
||||
setContentPane(contentPane);
|
||||
setModal(true);
|
||||
getRootPane().setDefaultButton(buttonOK);
|
||||
buttonOK.addActionListener(e -> {
|
||||
captcha = textField.getText();
|
||||
dispose();
|
||||
});
|
||||
}
|
||||
|
||||
public static CaptchaInputDialog create() {
|
||||
CaptchaInputDialog dialog = new CaptchaInputDialog();
|
||||
dialog.setTitle("Please input captcha");
|
||||
dialog.pack();
|
||||
dialog.setModal(true);
|
||||
dialog.setVisible(true);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public String getCookie() {
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public String getCaptcha() {
|
||||
return captcha;
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
try {
|
||||
cookie = new BilibiliAPI().getPassportService().getKey()
|
||||
.execute()
|
||||
.headers()
|
||||
.get("Set-cookie");
|
||||
Response response = Config.getBilibiliAPI().getPassportService()
|
||||
.getCaptcha(cookie)
|
||||
.execute();
|
||||
if (response.code() != 200) {
|
||||
throw new IOException(response.message());
|
||||
}
|
||||
label = new JLabel(new ImageIcon(ImageIO.read(response.body().byteStream())));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method generated by IntelliJ IDEA GUI Designer
|
||||
* >>> IMPORTANT!! <<<
|
||||
* DO NOT edit this method OR call it in your code!
|
||||
*
|
||||
* @noinspection ALL
|
||||
*/
|
||||
private void $$$setupUI$$$() {
|
||||
createUIComponents();
|
||||
contentPane = new JPanel();
|
||||
contentPane.setLayout(new GridBagLayout());
|
||||
contentPane.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2), null));
|
||||
final JPanel panel1 = new JPanel();
|
||||
panel1.setLayout(new GridBagLayout());
|
||||
panel1.setPreferredSize(new Dimension(200, 50));
|
||||
GridBagConstraints gbc;
|
||||
gbc = new GridBagConstraints();
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 1;
|
||||
gbc.weightx = 1.0;
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
contentPane.add(panel1, gbc);
|
||||
buttonOK = new JButton();
|
||||
buttonOK.setText("OK");
|
||||
gbc = new GridBagConstraints();
|
||||
gbc.gridx = 1;
|
||||
gbc.gridy = 0;
|
||||
gbc.weighty = 1.0;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
panel1.add(buttonOK, gbc);
|
||||
textField = new JTextField();
|
||||
gbc = new GridBagConstraints();
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
gbc.weightx = 1.0;
|
||||
gbc.weighty = 1.0;
|
||||
gbc.anchor = GridBagConstraints.WEST;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
panel1.add(textField, gbc);
|
||||
final JPanel panel2 = new JPanel();
|
||||
panel2.setLayout(new GridBagLayout());
|
||||
panel2.setPreferredSize(new Dimension(200, 50));
|
||||
gbc = new GridBagConstraints();
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
gbc.weightx = 1.0;
|
||||
gbc.weighty = 1.0;
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
contentPane.add(panel2, gbc);
|
||||
label.setText("Label");
|
||||
gbc = new GridBagConstraints();
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
gbc.weightx = 1.0;
|
||||
gbc.weighty = 1.0;
|
||||
gbc.anchor = GridBagConstraints.WEST;
|
||||
panel2.add(label, gbc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @noinspection ALL
|
||||
*/
|
||||
public JComponent $$$getRootComponent$$$() {
|
||||
return contentPane;
|
||||
}
|
||||
}
|
@ -1,12 +1,34 @@
|
||||
package com.hiczp.bilibili.api.test;
|
||||
|
||||
import com.hiczp.bilibili.api.passport.exception.CaptchaMismatchException;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class LoginTest {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LoginTest.class);
|
||||
private static final Config CONFIG = Config.getInstance();
|
||||
|
||||
@Test
|
||||
public void login() throws Exception {
|
||||
Config.getBilibiliAPI().login(CONFIG.getUsername(), CONFIG.getPassword());
|
||||
try {
|
||||
Config.getBilibiliAPI().login(CONFIG.getUsername(), CONFIG.getPassword());
|
||||
} catch (CaptchaMismatchException e) {
|
||||
LOGGER.info("Need captcha");
|
||||
if (GraphicsEnvironment.isHeadless()) {
|
||||
LOGGER.error("Need graphics support to display captcha, login failed");
|
||||
throw new UnsupportedOperationException(e);
|
||||
} else {
|
||||
CaptchaInputDialog captchaInputDialog = CaptchaInputDialog.create();
|
||||
Config.getBilibiliAPI().login(
|
||||
CONFIG.getUsername(),
|
||||
CONFIG.getPassword(),
|
||||
captchaInputDialog.getCaptcha(),
|
||||
captchaInputDialog.getCookie()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.hiczp.bilibili.api.BilibiliAPI;
|
||||
import com.hiczp.bilibili.api.BilibiliSecurityHelper;
|
||||
import com.hiczp.bilibili.api.ServerErrorCode;
|
||||
import com.hiczp.bilibili.api.passport.entity.LoginResponseEntity;
|
||||
import com.hiczp.bilibili.api.passport.entity.RefreshTokenResponseEntity;
|
||||
import org.junit.Test;
|
||||
@ -22,6 +23,10 @@ public class SecurityHelperTest {
|
||||
CONFIG.getUsername(),
|
||||
CONFIG.getPassword()
|
||||
);
|
||||
if (loginResponseEntity.getCode() == ServerErrorCode.Passport.CAPTCHA_NOT_MATCH) {
|
||||
LOGGER.error("This account need captcha to login, ignore test");
|
||||
return;
|
||||
}
|
||||
LOGGER.info("{}", GSON.toJson(loginResponseEntity));
|
||||
BilibiliSecurityHelper.logout(new BilibiliAPI(), loginResponseEntity.getData().getAccessToken());
|
||||
}
|
||||
@ -43,6 +48,10 @@ public class SecurityHelperTest {
|
||||
CONFIG.getUsername(),
|
||||
CONFIG.getPassword()
|
||||
);
|
||||
if (loginResponseEntity.getCode() == ServerErrorCode.Passport.CAPTCHA_NOT_MATCH) {
|
||||
LOGGER.error("This account need captcha to login, ignore test");
|
||||
return;
|
||||
}
|
||||
RefreshTokenResponseEntity refreshTokenResponseEntity = BilibiliSecurityHelper.refreshToken(
|
||||
new BilibiliAPI(),
|
||||
loginResponseEntity.getData().getAccessToken(),
|
||||
@ -69,6 +78,10 @@ public class SecurityHelperTest {
|
||||
CONFIG.getUsername(),
|
||||
CONFIG.getPassword()
|
||||
);
|
||||
if (loginResponseEntity.getCode() == ServerErrorCode.Passport.CAPTCHA_NOT_MATCH) {
|
||||
LOGGER.error("This account need captcha to login, ignore test");
|
||||
return;
|
||||
}
|
||||
String accessToken = loginResponseEntity.getData().getAccessToken();
|
||||
RefreshTokenResponseEntity refreshTokenResponseEntity = BilibiliSecurityHelper.refreshToken(
|
||||
new BilibiliAPI(),
|
||||
|
Loading…
Reference in New Issue
Block a user