mirror of
https://github.com/czp3009/bilibili-api.git
synced 2025-02-19 20:50:28 +08:00
完成 sso API
This commit is contained in:
parent
4694899ef9
commit
4e954af9d2
@ -10,7 +10,6 @@ apply plugin: 'signing'
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,17 @@
|
||||
package com.hiczp.bilibili.api;
|
||||
|
||||
import com.hiczp.bilibili.api.cookie.SimpleCookieJar;
|
||||
import com.hiczp.bilibili.api.interceptor.*;
|
||||
import com.hiczp.bilibili.api.live.LiveService;
|
||||
import com.hiczp.bilibili.api.live.socket.LiveClient;
|
||||
import com.hiczp.bilibili.api.passport.PassportService;
|
||||
import com.hiczp.bilibili.api.passport.SsoService;
|
||||
import com.hiczp.bilibili.api.passport.entity.InfoEntity;
|
||||
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.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.*;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -18,6 +19,7 @@ import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
@ -25,8 +27,9 @@ import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider {
|
||||
public class BilibiliAPI implements BilibiliServiceProvider, BilibiliSsoProvider, LiveClientProvider {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BilibiliAPI.class);
|
||||
|
||||
private final Long apiInitTime = Instant.now().getEpochSecond(); //记录当前类被实例化的时间
|
||||
@ -72,8 +75,6 @@ public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider
|
||||
public PassportService getPassportService(@Nonnull List<Interceptor> interceptors, @Nonnull HttpLoggingInterceptor.Level logLevel) {
|
||||
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
|
||||
|
||||
interceptors.forEach(okHttpClientBuilder::addInterceptor);
|
||||
|
||||
okHttpClientBuilder
|
||||
.addInterceptor(new AddFixedParamsInterceptor(
|
||||
"build", bilibiliClientProperties.getBuild(),
|
||||
@ -85,7 +86,11 @@ public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider
|
||||
))
|
||||
.addInterceptor(new AddAppKeyInterceptor(bilibiliClientProperties))
|
||||
.addInterceptor(new SortParamsAndSignInterceptor(bilibiliClientProperties))
|
||||
.addInterceptor(new ErrorResponseConverterInterceptor())
|
||||
.addInterceptor(new ErrorResponseConverterInterceptor());
|
||||
|
||||
interceptors.forEach(okHttpClientBuilder::addInterceptor);
|
||||
|
||||
okHttpClientBuilder
|
||||
.addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(logLevel));
|
||||
|
||||
return new Retrofit.Builder()
|
||||
@ -107,8 +112,6 @@ public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider
|
||||
public LiveService getLiveService(@Nonnull List<Interceptor> interceptors, @Nonnull HttpLoggingInterceptor.Level logLevel) {
|
||||
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
|
||||
|
||||
interceptors.forEach(okHttpClientBuilder::addInterceptor);
|
||||
|
||||
okHttpClientBuilder
|
||||
.addInterceptor(new AddFixedHeadersInterceptor(
|
||||
"Buvid", bilibiliClientProperties.getBuvId(),
|
||||
@ -144,7 +147,11 @@ public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider
|
||||
))
|
||||
.addInterceptor(new AddAccessKeyInterceptor(bilibiliAccount))
|
||||
.addInterceptor(new SortParamsAndSignInterceptor(bilibiliClientProperties))
|
||||
.addInterceptor(new ErrorResponseConverterInterceptor())
|
||||
.addInterceptor(new ErrorResponseConverterInterceptor());
|
||||
|
||||
interceptors.forEach(okHttpClientBuilder::addInterceptor);
|
||||
|
||||
okHttpClientBuilder
|
||||
.addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(logLevel));
|
||||
|
||||
return new Retrofit.Builder()
|
||||
@ -155,6 +162,45 @@ public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider
|
||||
.create(LiveService.class);
|
||||
}
|
||||
|
||||
public SsoService getSsoService() {
|
||||
return getSsoService(new SimpleCookieJar());
|
||||
}
|
||||
|
||||
//sso 需要保存 cookie, 不对 SsoService 进行缓存
|
||||
@Override
|
||||
public SsoService getSsoService(CookieJar cookieJar) {
|
||||
return getSsoService(cookieJar, Collections.emptyList(), HttpLoggingInterceptor.Level.BASIC);
|
||||
}
|
||||
|
||||
public SsoService getSsoService(@Nonnull CookieJar cookieJar, @Nonnull List<Interceptor> interceptors, @Nonnull HttpLoggingInterceptor.Level logLevel) {
|
||||
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
|
||||
|
||||
okHttpClientBuilder
|
||||
.cookieJar(cookieJar)
|
||||
.addInterceptor(new AddFixedParamsInterceptor(
|
||||
"build", bilibiliClientProperties.getBuild(),
|
||||
"mobi_app", "android",
|
||||
"platform", "android"
|
||||
))
|
||||
.addInterceptor(new AddDynamicParamsInterceptor(
|
||||
() -> "ts", () -> Long.toString(Instant.now().getEpochSecond())
|
||||
))
|
||||
.addInterceptor(new AddAccessKeyInterceptor(bilibiliAccount))
|
||||
.addInterceptor(new AddAppKeyInterceptor(bilibiliClientProperties))
|
||||
.addInterceptor(new SortParamsAndSignInterceptor(bilibiliClientProperties));
|
||||
|
||||
interceptors.forEach(okHttpClientBuilder::addInterceptor);
|
||||
|
||||
okHttpClientBuilder
|
||||
.addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(logLevel));
|
||||
|
||||
return new Retrofit.Builder()
|
||||
.baseUrl(BaseUrlDefinition.PASSPORT)
|
||||
.client(okHttpClientBuilder.build())
|
||||
.build()
|
||||
.create(SsoService.class);
|
||||
}
|
||||
|
||||
public LoginResponseEntity login(@Nonnull String username, @Nonnull String password) throws IOException, LoginException, CaptchaMismatchException {
|
||||
return login(username, password, null, null);
|
||||
}
|
||||
@ -270,6 +316,30 @@ public class BilibiliAPI implements BilibiliServiceProvider, LiveClientProvider
|
||||
return infoEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpUrl getSsoUrl(@Nullable String goUrl) {
|
||||
CancelRequestInterceptor cancelRequestInterceptor = new CancelRequestInterceptor();
|
||||
try {
|
||||
getSsoService(new SimpleCookieJar(), Collections.singletonList(cancelRequestInterceptor), HttpLoggingInterceptor.Level.BASIC)
|
||||
.sso(null)
|
||||
.execute();
|
||||
} catch (IOException ignored) {
|
||||
|
||||
}
|
||||
return cancelRequestInterceptor.getRequest().url();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<Cookie>> toCookies() throws IOException {
|
||||
return toCookies(BaseUrlDefinition.PASSPORT + "api/oauth2/getKey");
|
||||
}
|
||||
|
||||
public Map<String, List<Cookie>> toCookies(@Nullable String goUrl) throws IOException {
|
||||
SimpleCookieJar simpleCookieJar = new SimpleCookieJar();
|
||||
getSsoService(simpleCookieJar).sso(goUrl).execute();
|
||||
return simpleCookieJar.getCookiesMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveClient getLiveClient(long showRoomId) {
|
||||
return bilibiliAccount.getUserId() == null ?
|
||||
|
@ -0,0 +1,20 @@
|
||||
package com.hiczp.bilibili.api;
|
||||
|
||||
import com.hiczp.bilibili.api.passport.SsoService;
|
||||
import okhttp3.Cookie;
|
||||
import okhttp3.CookieJar;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface BilibiliSsoProvider {
|
||||
SsoService getSsoService(CookieJar cookieJar);
|
||||
|
||||
//获取用于进行 sso 登录的初始 URL
|
||||
HttpUrl getSsoUrl(String goUrl);
|
||||
|
||||
//获取当前 token 对应的 cookies
|
||||
Map<String, List<Cookie>> toCookies() throws IOException;
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package com.hiczp.bilibili.api.cookie;
|
||||
|
||||
import okhttp3.Cookie;
|
||||
import okhttp3.CookieJar;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SimpleCookieJar implements CookieJar {
|
||||
private Map<String, List<Cookie>> cookiesMap;
|
||||
|
||||
public SimpleCookieJar() {
|
||||
cookiesMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public SimpleCookieJar(Map<String, List<Cookie>> cookiesMap) {
|
||||
this.cookiesMap = new HashMap<>(cookiesMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
|
||||
cookies.forEach(cookie -> {
|
||||
String domain = cookie.domain();
|
||||
List<Cookie> savedCookies = cookiesMap.get(domain);
|
||||
if (savedCookies == null) {
|
||||
savedCookies = new ArrayList<>();
|
||||
savedCookies.add(cookie);
|
||||
cookiesMap.put(domain, savedCookies);
|
||||
} else {
|
||||
for (Cookie savedCookie : savedCookies) {
|
||||
if (savedCookie.name().equals(cookie.name())) {
|
||||
savedCookies.remove(savedCookie);
|
||||
break;
|
||||
}
|
||||
}
|
||||
savedCookies.add(cookie);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cookie> loadForRequest(HttpUrl url) {
|
||||
return getCookiesForHost(url.host());
|
||||
}
|
||||
|
||||
public List<Cookie> getCookiesForHost(String host) {
|
||||
List<Cookie> cookieList = new ArrayList<>();
|
||||
cookiesMap.forEach((domain, cookies) -> {
|
||||
if (host.endsWith(domain)) {
|
||||
for (int i = cookies.size() - 1; i >= 0; i--) {
|
||||
if (cookies.get(i).expiresAt() < System.currentTimeMillis()) {
|
||||
cookies.remove(i);
|
||||
}
|
||||
}
|
||||
cookieList.addAll(cookies);
|
||||
}
|
||||
});
|
||||
return cookieList;
|
||||
}
|
||||
|
||||
public Map<String, List<Cookie>> getCookiesMap() {
|
||||
return cookiesMap;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.hiczp.bilibili.api.exception;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class UserCancelRequestException extends IOException {
|
||||
public UserCancelRequestException() {
|
||||
|
||||
}
|
||||
|
||||
public UserCancelRequestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UserCancelRequestException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public UserCancelRequestException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.hiczp.bilibili.api.interceptor;
|
||||
|
||||
import com.hiczp.bilibili.api.exception.UserCancelRequestException;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CancelRequestInterceptor implements Interceptor {
|
||||
private Request request;
|
||||
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
request = chain.request();
|
||||
throw new UserCancelRequestException();
|
||||
}
|
||||
|
||||
public Request getRequest() {
|
||||
return request;
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@ import retrofit2.http.POST;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface PassportService {
|
||||
//获取验证码
|
||||
@ -50,9 +49,4 @@ public interface PassportService {
|
||||
|
||||
@POST("api/oauth2/revoke")
|
||||
Call<LogoutResponseEntity> logout(@Query("access_token") String accessToken);
|
||||
|
||||
//TODO sso 尚不明确
|
||||
@Deprecated
|
||||
@GET("api/login/sso")
|
||||
Call sso(@Query("access_token") String accessToken, @Nullable @Query("gourl") String goUrl);
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
package com.hiczp.bilibili.api.passport;
|
||||
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
//sso 很特别, 它可能返回的是一个 HTML 页面, 所以单独分出来
|
||||
//sso 会经过两次 302 跳转, 需要保存其中的 cookie, 然后才能抵达最终页面并且进入 cookie 登录状态
|
||||
public interface SsoService {
|
||||
@GET("api/login/sso")
|
||||
Call<ResponseBody> sso(@Nullable @Query("gourl") String goUrl);
|
||||
}
|
@ -1,25 +1,28 @@
|
||||
package com.hiczp.bilibili.api.test;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.hiczp.bilibili.api.BilibiliAPI;
|
||||
import org.junit.Ignore;
|
||||
import okhttp3.Cookie;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SsoTest {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(UserInfoTest.class);
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SsoTest.class);
|
||||
private static final BilibiliAPI BILIBILI_API = Config.getBilibiliAPI();
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
// Object object = BILIBILI_API.getPassportService()
|
||||
// .sso(BILIBILI_API.getBilibiliAccount().getAccessToken(), null)
|
||||
// .execute()
|
||||
// .body();
|
||||
// LOGGER.info("{}", object.toString());
|
||||
Map<String, List<Cookie>> cookiesMap = BILIBILI_API.toCookies();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
cookiesMap.forEach((domain, cookies) -> {
|
||||
stringBuilder.append("domain: ").append(domain).append("\n");
|
||||
cookies.forEach(cookie ->
|
||||
stringBuilder.append("\t").append(cookie.name()).append("=").append(cookie.value()).append("\n")
|
||||
);
|
||||
});
|
||||
LOGGER.info("Cookies below: \n{}", stringBuilder.toString());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user