這是在一系列 Retrofit 文章的第二篇, 它介紹了怎麼在 Retrofit 裏集成 base authentication。
Retrofit 系列文章概覽
- 基礎入門
- 用 Retrofit 實現 Basic Authentication
在基礎入門裏,我們創建了一個初始的 client 去執行 API/HTTP 請求。我們將上一篇文章裏創建的 client 爲基礎,然後在它上面擴展功能來進行 basic authentication。你也可以再次閱讀基礎入門去獲取更多關於創建 client 端的信息。
集成 Basic Authentication
我們先更新 ServiceGenerator
類然後創建一個方法在請求中添加 authentication header。下面的代碼片段擴展了上一篇文章 的 ServiceGenerator
類。在 Retrofit 1.9的代碼下面,我們添加了 Retrofit 2的示範代碼。如果你使用了新版本的 Retrofit,可以直接跳到下面看第二塊代碼:)
Retrofit 1.9
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(API_BASE_URL)
.setClient(new OkClient(new OkHttpClient()));
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(Class<S> serviceClass, String username, String password) {
if (username != null && password != null) {
// concatenate username and password with colon for authentication
String credentials = username + ":" + password;
// create Base64 encodet string
final String basic =
"Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
builder.setRequestInterceptor(new RequestInterceptor() {
@Override
public void intercept(RequestFacade request) {
request.addHeader("Authorization", basic);
request.addHeader("Acceppt", "application/json");
}
});
}
RestAdapter adapter = builder.build();
return adapter.create(serviceClass);
}
}
Retrofit 2
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static OkHttpClient httpClient = new OkHttpClient();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(Class<S> serviceClass, String username, String password) {
if (username != null && password != null) {
String credentials = username + ":" + password;
final String basic =
"Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
httpClient.interceptors().clear();
httpClient.interceptors().add(new Interceptor() {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", basic);
.header("Accept", "applicaton/json");
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
}
Retrofit retrofit = builder.client(httpClient).build();
return retrofit.create(serviceClass);
}
}
這個新的 createService
方法多了兩個參數:username 和 password。username 也可以使用 email。創建 client 的基本過程與原來相同:使用 RestAdapter
(在Retrofit2裏使用 Retrofit
)類創建一個 OkHttp client 去處理所有的 http 請求和響應。
不同的地方在於: 我們用 RequestInterceptor
(在Retrofit2裏使用 Interceptor
)爲每一個通過這個 OkHttp client 的 http 請求設置 Authorization header。但是這個只有在提供 username 和 password 的情況下才會做。如果你不提供 username 和 password ,它將會創建一個和上篇文章裏一樣的 client 。因此我們可以簡化 ServiceGenerator
類的第一個方法。
對於認證部分,我們必須調整給定的 username/email 和 password 的格式。Basic authentication 要求把這兩個值組成一個用冒號分隔的字符串,然後把這個新組成的字符串用 Base64 編碼。
幾乎所有的 webservice 和 API 驗證 Authorization header,因此我們把編碼後的內容放到它裏面,如果你調用的webservice指定了另一個header field來獲取內容,你只要調整 Authorization 爲它指定的 field。
如果你想從服務器收到一個指定格式的響應,那麼 Accept header 是必需的,在我們的例子裏,我們想要JSON格式的響應,既然 Retrofit 已經使用 GSON 來把服務端的響應轉成我們需要的類型。
使用
只需調用 ServiceGenerator
類的新的方法,就像在基礎入門文章裏那樣。首先我們定義一個 LoginService
。
Retrofit 1.9
public interface LoginService {
@POST("/login")
User basicLogin();
}
Retrofit 2
public interface LoginService {
@POST("/login")
Call<User> basicLogin();
}
上面的接口只有一個方法: basicLogin
。它有一個 User
類型的返回值,並且它不需要額外的 query 或 path 參數。
現在你可以傳遞你的認證信息 ( username, password ) 來創建一個 HTTP client 。
Retrofit 1.9
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
User user = loginService.basicLogin();
Retrofit 2
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
Call<User> call = loginService.basicLogin();
User user = call.execute().body();
ServiceGenerator
裏面的方法會自動創建含有認證信息 HTTP client,只要你調用 loginService
的 basicLogin
方法。你提供的認證信息會自動的發送給後端API。