2. Retrofit2 -- Basic Authentication on Android
上一節課中,我們創建了用於執行 API/HTTP
請求的原始 Android
客戶端版本。本節課中,我們將使用上節課的客戶端,對它進行增強,給它添加基本的認證功能。
整合基本的認證
首先,更新 ServiceGenerator
類,添加方法,用於把認證添加到請求上。下面的代碼使用 1.9
、2.0
版本分別進行了擴展:
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("Accept", "application/json");
- }
- });
- }
-
- RestAdapter adapter = builder.build();
- return adapter.create(serviceClass);
- }
- }
Retrofit 2.0
- public class ServiceGenerator {
-
- public static final String API_BASE_URL = "https://your.api-base.url";
-
- private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
-
- 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.addInterceptor(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", "application/json")
- .method(original.method(), original.body());
-
- Request request = requestBuilder.build();
- return chain.proceed(request);
- }
- });
- }
-
- OkHttpClient client = httpClient.build();
- Retrofit retrofit = builder.client(client).build();
- return retrofit.create(serviceClass);
- }
- }
新方法中,多了兩個參數:username
和 password
。創建客戶端的基本方法與老方法一樣:使用 RestAdapter
(2.0
版本是 Retrofit
)類為所有的 HTTP
請求和響應處理創建 OKHttp
客戶端。
新方法的不同在於:使用了 RequestInterceptor
(2.0
版本是 Inteceptor
)類來為 OKHttp
客戶端執行的 HTTP
請求設置認證的頭部。當然,只有提供了 username
和 password
參數,才會設置的。如果該方法沒有接收到 username
和 password
參數,那么它創建的客戶端與第一個方法相同。
關於驗證部分,我們必須調整 username
和 password
的格式。基本認證請求把所有值當作一個以逗號分隔的多行索引字符串。此外,新創建的字符串必須是 Base64
格式的編碼。
大多數的 webservice
和 API
都會對 HTTP
請求的認證頭部進行計算。這就是為什么我們要把編碼認證的值設置到頭部。如果你調用 web
服務的客戶端使用了其它的頭部字段來接收用戶的認證,那你應該把頭部的 Authorization
轉換為你服務所需的字段。
如果你想使用某種特定的格式來接收服務響應,那么,Accept
頭部字段起着決定性的作用。在示例中,我們要求服務器返回的信息格式是 JSON
。這是因為我們配置了 retrofit
使用 Google GSON
把序列化的對象和 JSON
互相轉換。
用法
新方法的調用方法與上節課舊方法的調用方法一樣。假定,我們定義了一個 LoginService
:
Retrofit 1.9
- public interface LoginService {
- @POST("/login")
- void basicLogin(Callback<User> cb);
- }
Retrofit 2.0
- public interface LoginService {
- @POST("/login")
- Call<User> basicLogin();
- }
上面的接口只有一個方法:basicLogin
。它的響應值類型是:User
,沒有其它的查詢、或路徑參數。
現在,我們創建一個客戶端並把認證信息(username password
)傳入:
Retrofit 1.9
- LoginService loginService =
- ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
- loginService.basicLogin(new Callback<User>() {
- @Override
- public void success(User user, Response response) {
- // user object available
- }
-
- @Override
- public void failure(RetrofitError error) {
- // handle errors, too
- }
- });
Retrofit 2.0
- LoginService loginService =
- ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
- Call<User> call = loginService.basicLogin();
- call.enqueue(new Callback<User >() {
- @Override
- public void onResponse(Call<User> call, Response<User> response) {
- if (response.isSuccessful()) {
- // user object available
- } else {
- // error response, no access to resource?
- }
- }
-
- @Override
- public void onFailure(Call<User> call, Throwable t) {
- // something went completely south (like no internet connection)
- Log.d("Error", t.getMessage());
- }
- }
ServiceGenerator
方法將創建包含預定義認證頭部的 HTTP
客戶端。一旦調用 loginService
的 basicLogin
方法,提供的認證信息將自動被傳入到請求的 API
端點。