这是使用翻新2设置基本身份验证的正确方法吗?

时间:2018-07-29 10:17:07

标签: android retrofit2 basic-authentication okhttp3

我正在做一个辅助项目,我所知道的是我应该使用基本身份验证。由于我没有使用它的经验,因此我在网上找到了一些东西,我想请您征求意见,这是正确的方法吗...

因此,第一件事来自Retrofit的文档:

这是翻新(网络)设置:

public class RetrofitSetup {

public static final String 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());

private static Retrofit retrofit = builder.build();

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 (!TextUtils.isEmpty(username)
            && !TextUtils.isEmpty(password)) {
        String authToken = Credentials.basic(username, password);
        return createService(serviceClass, authToken);
    }

    return createService(serviceClass, null);
}

public static <S> S createService(
        Class<S> serviceClass, final String authToken) {
    if (!TextUtils.isEmpty(authToken)) {
        AuthenticationInterceptor interceptor =
                new AuthenticationInterceptor(authToken);

        if (!httpClient.interceptors().contains(interceptor)) {
            httpClient.addInterceptor(interceptor);

            builder.client(httpClient.build());
            retrofit = builder.build();
        }
    }

    return retrofit.create(serviceClass);
}

}

和身份验证拦截器:

public class AuthenticationInterceptor implements Interceptor {

private String authToken;

public AuthenticationInterceptor(String token) {
    this.authToken = token;
}

@Override
public Response intercept(@NonNull Chain chain) throws IOException {
    Request original = chain.request();

    Request.Builder builder = original.newBuilder()
            .header("Authorization", authToken);

    Request request = builder.build();
    return chain.proceed(request);
}
}

这是我的RetrofitSerive课:

public interface RetrofitService {

@GET("login")
Call<Void> basicLogin();

@GET("contact")
Call<List<Contacts>> getContacts(@Header("Authorization") String authkey);

@GET("product")
Call<List<Products>> getProducts(@Header("Authorization") String authkey);

}

还有我在网上找到的用于生成身份验证密钥的类:

public class Helper {
public static String getAuthToken(String username, String password) {
    byte[] data = new byte[0];
    try {
        data = (username + ":" + password).getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
        return "Failed to authenticate";
    }
    return "Basic " + Base64.encodeToString(data, Base64.NO_WRAP);
}
}

我相信这里没有什么可更改的...所以第一件事是登录(检查身份验证),这是我想知道如何正确做的几件事:

private void login(final String username, final String password) {
    RetrofitService loginService =
            RetrofitSetup.createService(RetrofitService.class, username, password);
    Call<Void> call = loginService.basicLogin();
    call.enqueue(new Callback<Void>() {
        @Override
        public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) {
            progressBar.setVisibility(View.GONE);
            if (response.isSuccessful()) {
                // user object available
                editor.putString("username", username);
                editor.putString("password", password);
                editor.apply();
                startActivity(new Intent(LoginActivity.this, MainActivity.class));
                finish();
            } else {
                Toast.makeText(LoginActivity.this, response.message(), Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
            progressBar.setVisibility(View.GONE);
            Toast.makeText(LoginActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });
}

如果响应成功,我会将这些凭据保存在SharedPreferences中。

下一页应该调用另一个请求,所以我想同时发送用户名/密码或身份验证密钥是否有区别?

这是我的方法:

private void getContacts() {
    prefs = getActivity().getSharedPreferences(KEY, MODE_PRIVATE);
    String username = prefs.getString("username", null);
    String password = prefs.getString("password", null);

    RetrofitService loginService =
            RetrofitSetup.createService(RetrofitService.class, Helper.getAuthToken(username, password));
    Call<List<Contacts>> call = loginService.getContacts(Helper.getAuthToken(username, password));
    call.enqueue(new Callback<List<Contacts>>() {
        @Override
        public void onResponse(@NonNull Call<List<Contacts>> call, @NonNull Response<List<Contacts>> response) {
            if (response.isSuccessful()) {
                kontaktiAdapter.setKontakti(response.body());
            } else {
                Toast.makeText(getActivity(), response.message(), Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onFailure(@NonNull Call<List<Contacts>> call, @NonNull Throwable t) {
            Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });
}

因此,在此呼叫中,不是将用户名/密码发送到RetrofitSetup.createService,而是从SharedPreferences发送带有用户名和密码的Helper.getAuthToken(用户名,密码)。

这是正确的方法吗?如果退出该应用程序,则在登录屏幕中,我正在检查SharedPreferences是否包含用户名/密码,并尝试使用这些参数登录。不包含它们,因此用户将无法登录,他/她将不得不再次输入这些信息...

您对此有何看法,有什么我应该做不同的事情吗? 问候!

1 个答案:

答案 0 :(得分:0)

这是迄今为止我尝试过的最简单的“基本身份验证”方法。

使用以下代码生成auth标头(API /存储库类)

 var basic = Credentials.basic("YOUR_USERNAME", "YOUR_PASSWORD")

将此作为标头传递到Web服务调用(API /存储库类)

 var retrofitCall = myWebservice.getNewsFeed(basic)

添加基本标头作为参数(Retrofit Web服务接口类)

 @GET("newsfeed/daily")
 fun getNewsFeed(@Header("Authorization") h1:String):Call<NewsFeedResponse>

对不起,我的代码在Kotlin中,但是可以轻松地翻译成Java。