From 08454d48ff9309fb7ebc6b7d4b0534e6c89bb237 Mon Sep 17 00:00:00 2001 From: czp Date: Thu, 1 Feb 2018 14:33:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=94=99=E8=AF=AF=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- .../bilibili/api/BilibiliSecurityHelper.java | 19 +--- .../hiczp/bilibili/api/ServerErrorCode.java | 22 +++-- .../api/passport/PassportService.java | 6 ++ .../hiczp/bilibili/api/test/LoginTest.java | 12 +++ .../hiczp/bilibili/api/test/LogoutTest.java | 10 ++ .../hiczp/bilibili/api/test/RuleSuite.java | 20 +--- .../bilibili/api/test/SecurityHelperTest.java | 95 +++++++++++++++++++ 8 files changed, 149 insertions(+), 37 deletions(-) create mode 100644 src/test/java/com/hiczp/bilibili/api/test/LoginTest.java create mode 100644 src/test/java/com/hiczp/bilibili/api/test/LogoutTest.java create mode 100644 src/test/java/com/hiczp/bilibili/api/test/SecurityHelperTest.java diff --git a/build.gradle b/build.gradle index 32f4af4..dc87009 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group = 'com.hiczp' -version = '0.0.2' +version = '0.0.3' description = 'Bilibili android client API library written in Java' apply plugin: 'idea' diff --git a/src/main/java/com/hiczp/bilibili/api/BilibiliSecurityHelper.java b/src/main/java/com/hiczp/bilibili/api/BilibiliSecurityHelper.java index c78f274..062872b 100644 --- a/src/main/java/com/hiczp/bilibili/api/BilibiliSecurityHelper.java +++ b/src/main/java/com/hiczp/bilibili/api/BilibiliSecurityHelper.java @@ -5,8 +5,6 @@ import com.hiczp.bilibili.api.passport.entity.KeyEntity; 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 org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -25,8 +23,6 @@ import java.util.Base64; import java.util.stream.Collectors; public class BilibiliSecurityHelper { - private static final Logger LOGGER = LoggerFactory.getLogger(BilibiliSecurityHelper.class); - public static LoginResponseEntity login(BilibiliServiceProvider bilibiliServiceProvider, String username, String password) throws IOException, LoginException { @@ -72,7 +68,6 @@ public class BilibiliSecurityHelper { //判断返回值 switch (loginResponseEntity.getCode()) { case ServerErrorCode.Common.OK: { - LOGGER.info("Login succeed with username '{}', userId: {}", username, loginResponseEntity.getData().getMid()); return loginResponseEntity; } case ServerErrorCode.Passport.USERNAME_OR_PASSWORD_INVALID: { @@ -81,6 +76,9 @@ public class BilibiliSecurityHelper { case ServerErrorCode.Passport.CANT_DECRYPT_RSA_PASSWORD: { throw new LoginException("password error or hash expired"); } + case ServerErrorCode.Passport.CAPTCHA_NOT_MATCH: { + throw new LoginException(loginResponseEntity.getMessage()); + } default: { //其他错误码 throw new IOException(loginResponseEntity.getMessage()); @@ -99,13 +97,9 @@ public class BilibiliSecurityHelper { .body(); switch (refreshTokenResponseEntity.getCode()) { case ServerErrorCode.Common.OK: { - LOGGER.info("Access token refreshed, Expires in {} seconds later", refreshTokenResponseEntity.getData().getExpiresIn()); return refreshTokenResponseEntity; } - case ServerErrorCode.Common.NO_LOGIN: { - throw new LoginException("access token can't be empty"); - } - case ServerErrorCode.Passport.ACCESS_TOKEN_NOT_FOUND: { + case ServerErrorCode.Passport.NO_LOGIN: { throw new LoginException("access token invalid"); } case ServerErrorCode.Passport.REFRESH_TOKEN_NOT_MATCH: { @@ -125,10 +119,7 @@ public class BilibiliSecurityHelper { case ServerErrorCode.Common.OK: { return logoutResponseEntity; } - case ServerErrorCode.Common.NO_LOGIN: { - throw new LoginException("access token can't be empty or invalid"); - } - case ServerErrorCode.Passport.ACCESS_TOKEN_NOT_FOUND: { + case ServerErrorCode.Passport.NO_LOGIN: { throw new LoginException("access token invalid"); } default: { diff --git a/src/main/java/com/hiczp/bilibili/api/ServerErrorCode.java b/src/main/java/com/hiczp/bilibili/api/ServerErrorCode.java index 4bf3e92..45b42f7 100644 --- a/src/main/java/com/hiczp/bilibili/api/ServerErrorCode.java +++ b/src/main/java/com/hiczp/bilibili/api/ServerErrorCode.java @@ -2,30 +2,40 @@ package com.hiczp.bilibili.api; //不知道为什么错误码都要加负号 public class ServerErrorCode { + //服务网关上鉴权失败的话, 会返回这些标准错误码 + //B站后台设计很混乱, 不是所有鉴权都在服务网关上完成 public static class Common { public static final int OK = 0; - public static final int NO_LOGIN = -101; public static final int BAD_REQUEST = -400; - //message 可能为 Illegal request + public static final int UNAUTHORIZED = -401; public static final int FORBIDDEN = -403; public static final int NOT_FOUND = -404; public static final int INTERNAL_SERVER_ERROR = -500; } + //现在 access token 错误统一返回 -101 public static class Passport { + //"access_key not found" + public static final int NO_LOGIN = -101; + //短时间内进行多次错误的登录将被要求输入验证码 + public static final int CAPTCHA_NOT_MATCH = -105; //用户名不存在 public static final int USERNAME_OR_PASSWORD_INVALID = -629; //密码不可解密或者密码错误 public static final int CANT_DECRYPT_RSA_PASSWORD = -662; - public static final int ACCESS_TOKEN_NOT_FOUND = -901; + @Deprecated + public static final int ACCESS_TOKEN_NOT_FOUND = -901; //B站换了错误码, 现在 "access_key not found." 对应 -101 public static final int REFRESH_TOKEN_NOT_MATCH = -903; } + //一些 API 未登录时返回 3, 一些返回 -101, 还有一些返回 401, 在网关上鉴权的 API 返回 -401 public static class Live { - //访问 isFollowed 时如果未登录, 返回的是 3, message 是 "user no login" - //正常的 API 如果未登录, 返回的是 -101 + //"user no login" public static final int USER_NO_LOGIN = 3; - public static final int NOT_FOUND = -404; + //"请登录" + public static final int PLEASE_LOGIN = 401; + //"请先登录" + public static final int NO_LOGIN = -101; //已经领取过这个宝箱 public static final int THIS_SILVER_TASK_ALREADY_TOOK = -903; //今天所有的宝箱已经领完 diff --git a/src/main/java/com/hiczp/bilibili/api/passport/PassportService.java b/src/main/java/com/hiczp/bilibili/api/passport/PassportService.java index 1acf531..1e845a9 100644 --- a/src/main/java/com/hiczp/bilibili/api/passport/PassportService.java +++ b/src/main/java/com/hiczp/bilibili/api/passport/PassportService.java @@ -13,6 +13,12 @@ public interface PassportService { @POST("api/oauth2/login") Call login(@Query("username") String username, @Query("password") String password); + //在一段时间内进行多次错误的登录, 将被要求输入验证码 + //TODO 尚不明确 captcha 是如何工作的 + @Deprecated + @POST("api/oauth2/login") + Call loginWithCaptcha(@Query("username") String username, @Query("password") String password, @Query("captcha") String captcha); + @GET("api/oauth2/info") Call getInfo(@Query("access_token") String accessToken); diff --git a/src/test/java/com/hiczp/bilibili/api/test/LoginTest.java b/src/test/java/com/hiczp/bilibili/api/test/LoginTest.java new file mode 100644 index 0000000..03fad96 --- /dev/null +++ b/src/test/java/com/hiczp/bilibili/api/test/LoginTest.java @@ -0,0 +1,12 @@ +package com.hiczp.bilibili.api.test; + +import org.junit.Test; + +public class LoginTest { + private static final Config CONFIG = Config.getInstance(); + + @Test + public void login() throws Exception { + Config.getBilibiliAPI().login(CONFIG.getUsername(), CONFIG.getPassword()); + } +} diff --git a/src/test/java/com/hiczp/bilibili/api/test/LogoutTest.java b/src/test/java/com/hiczp/bilibili/api/test/LogoutTest.java new file mode 100644 index 0000000..7028ce7 --- /dev/null +++ b/src/test/java/com/hiczp/bilibili/api/test/LogoutTest.java @@ -0,0 +1,10 @@ +package com.hiczp.bilibili.api.test; + +import org.junit.Test; + +public class LogoutTest { + @Test + public void logout() throws Exception { + Config.getBilibiliAPI().logout(); + } +} diff --git a/src/test/java/com/hiczp/bilibili/api/test/RuleSuite.java b/src/test/java/com/hiczp/bilibili/api/test/RuleSuite.java index b2c1677..f8d000b 100644 --- a/src/test/java/com/hiczp/bilibili/api/test/RuleSuite.java +++ b/src/test/java/com/hiczp/bilibili/api/test/RuleSuite.java @@ -7,17 +7,18 @@ import org.junit.rules.ExternalResource; import org.junit.runner.RunWith; import org.junit.runners.Suite; -import javax.security.auth.login.LoginException; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStreamReader; @RunWith(Suite.class) @Suite.SuiteClasses({ + LoginTest.class, UserInfoTest.class, LiveClientTest.class, SsoTest.class, - SendBulletScreenTest.class + SendBulletScreenTest.class, + SecurityHelperTest.class, + LogoutTest.class }) public class RuleSuite { @ClassRule @@ -38,19 +39,6 @@ public class RuleSuite { //抛出异常就可以取消测试 throw new RuntimeException("Please create config file before tests"); } - - Config config = Config.getInstance(); - //登录 - Config.getBilibiliAPI().login(config.getUsername(), config.getPassword()); - } - - @Override - protected void after() { - try { - Config.getBilibiliAPI().logout(); - } catch (IOException | LoginException e) { - e.printStackTrace(); - } } }; } diff --git a/src/test/java/com/hiczp/bilibili/api/test/SecurityHelperTest.java b/src/test/java/com/hiczp/bilibili/api/test/SecurityHelperTest.java new file mode 100644 index 0000000..fde3a9c --- /dev/null +++ b/src/test/java/com/hiczp/bilibili/api/test/SecurityHelperTest.java @@ -0,0 +1,95 @@ +package com.hiczp.bilibili.api.test; + +import com.hiczp.bilibili.api.BilibiliAPI; +import com.hiczp.bilibili.api.BilibiliSecurityHelper; +import com.hiczp.bilibili.api.passport.entity.LoginResponseEntity; +import com.hiczp.bilibili.api.passport.entity.RefreshTokenResponseEntity; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.security.auth.login.LoginException; + +public class SecurityHelperTest { + private static final Logger LOGGER = LoggerFactory.getLogger(SecurityHelperTest.class); + private static final Config CONFIG = Config.getInstance(); + + @Test + public void normalLogin() throws Exception { + LOGGER.info("Login attempt with username {}", CONFIG.getUsername()); + LoginResponseEntity loginResponseEntity = BilibiliSecurityHelper.login( + new BilibiliAPI(), + CONFIG.getUsername(), + CONFIG.getPassword() + ); + LOGGER.info("Login succeed with username {}", CONFIG.getUsername()); + BilibiliSecurityHelper.logout(new BilibiliAPI(), loginResponseEntity.getData().getAccessToken()); + } + + @Test + public void loginWithWrongUsername() throws Exception { + final String username = "bilibili_account"; + final String password = "bilibili_password"; + LOGGER.info("Login attempt with username {}, password {}", username, password); + try { + BilibiliSecurityHelper.login( + new BilibiliAPI(), + username, + password + ); + } catch (LoginException e) { + e.printStackTrace(); + } + } + + @Test + public void normalRefreshToken() throws Exception { + LOGGER.info("Login attempt with username {}", CONFIG.getUsername()); + LoginResponseEntity loginResponseEntity = BilibiliSecurityHelper.login( + new BilibiliAPI(), + CONFIG.getUsername(), + CONFIG.getPassword() + ); + LOGGER.info("Login succeed with access token {}", loginResponseEntity.getData().getAccessToken()); + RefreshTokenResponseEntity refreshTokenResponseEntity = BilibiliSecurityHelper.refreshToken( + new BilibiliAPI(), + loginResponseEntity.getData().getAccessToken(), + loginResponseEntity.getData().getRefreshToken() + ); + LOGGER.info("Refresh token succeed with new access token {}", refreshTokenResponseEntity.getData().getAccessToken()); + BilibiliSecurityHelper.logout(new BilibiliAPI(), refreshTokenResponseEntity.getData().getAccessToken()); + } + + @Test + public void refreshTokenWithWrongToken() throws Exception { + try { + RefreshTokenResponseEntity refreshTokenResponseEntity = BilibiliSecurityHelper.refreshToken( + new BilibiliAPI(), + "token", + "refreshToken" + ); + } catch (LoginException e) { + e.printStackTrace(); + } + } + + @Test + public void refreshTokenWithWrongRefreshToken() throws Exception { + LoginResponseEntity loginResponseEntity = BilibiliSecurityHelper.login( + new BilibiliAPI(), + CONFIG.getUsername(), + CONFIG.getPassword() + ); + String accessToken = loginResponseEntity.getData().getAccessToken(); + LOGGER.info("Login succeed with access token {}", accessToken); + try { + RefreshTokenResponseEntity refreshTokenResponseEntity = BilibiliSecurityHelper.refreshToken( + new BilibiliAPI(), + accessToken, + "refreshToken" + ); + } catch (LoginException e) { + e.printStackTrace(); + } + } +}