首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >这是使用Retrofit 2设置基本身份验证的正确方法吗?

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

Stack Overflow用户
提问于 2018-07-29 18:17:07
回答 1查看 147关注 0票数 0

我正在做一个小项目,我所知道的就是我应该使用基本认证。由于我没有使用它的经验,我在网上找到了一些东西,我想征求你的意见,这是正确的方法吗…

所以,第一件事来自于Retrofit的文档:

这是Retrofit(网络)设置:

代码语言:javascript
运行
复制
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);
}

}

和身份验证拦截器:

代码语言:javascript
运行
复制
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类:

代码语言:javascript
运行
复制
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);

}

和我在网上找到的生成auth key的类:

代码语言:javascript
运行
复制
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);
}
}

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

代码语言:javascript
运行
复制
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中。

下一页应该调用另一个请求,所以我想知道如果我同时发送用户名/密码或身份验证密钥会有什么不同?

我是这样做的:

代码语言:javascript
运行
复制
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是否包含用户名/密码,并尝试使用这些参数登录。如果我想注销,我从SharedPreferences中清除这些参数,这样下次用户打开应用程序时,SharedPreferences将不会包含它们,所以用户将不会登录,他/她将不得不再次键入这些参数……

你对此有什么看法,有没有什么我应该做的不一样的?致以问候!

EN

回答 1

Stack Overflow用户

发布于 2018-10-09 14:21:49

到目前为止,这是我尝试过的最简单的“基本身份验证”方法。

使用以下代码生成auth头(API/Repository类)

代码语言:javascript
运行
复制
 var basic = Credentials.basic("YOUR_USERNAME", "YOUR_PASSWORD")

将其作为头部传递给the服务调用(API/Repository类)

代码语言:javascript
运行
复制
 var retrofitCall = myWebservice.getNewsFeed(basic)

添加基本头部作为参数(Retrofit Webservice接口类)

代码语言:javascript
运行
复制
 @GET("newsfeed/daily")
 fun getNewsFeed(@Header("Authorization") h1:String):Call<NewsFeedResponse>

对不起,我的代码是Kotlin的,但是可以很容易地翻译成Java。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51579299

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档