Retrofit2拦截器,只在特定方法中使用token

Retrofit2 interceptor, using token only in specific methods

我想在 Retrofit2 中使用 authorization。我选择了 interceptor 方式,因为几乎所有方法都需要 authorization,除了我正在获取令牌以进一步用于其他方法的方法。

我的问题是:我怎样才能做到这一点?

我将访问令牌存储在 SharedPreferences 中。我的第一个想法是:“我可以在我的 RetrofitClient class 中检索它,并根据令牌是否为 null 或它是否具有值来创建合适的 Retrofit 实例 "(添加或不添加 .client()

不幸的是,这并不容易,因为需要 Context 才能获得偏好。

我不知道如何将它传递到 RetrofitClient class 或如何进入它。

这是我的 RetrofitClient class:

public class RetrofitClient {

    public static final String BASE_URL = "http://localhost";
    public static Retrofit retrofit = null;

    private RetrofitClient() {
        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                //.client(getRequestHeader())
                .build();
    }

    /*OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request newRequest = chain.request().newBuilder()
                    .addHeader("Authorization", "Bearer" + )
        }
    })*/

    public static synchronized Retrofit getInstance() {
        if (retrofit == null) {

            retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create()).build();
        }
        return retrofit;
    }

    public Api getApi() {
        return retrofit.create(Api.class);
    }
}

我的 getRequestHeader() 是我之前设置超时的方法。

我想创建这样的实例:

private RetrofitClient() {
            tokenService.token = null;
            tokenService.readToken(ApplicationContext.getInstance());


            if (tokenService.token == null) {
                retrofit = new Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
            } else {
                retrofit = new Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .addConverterFactory(GsonConverterFactory.create())
                        .client(client) //I have interceptor here with access token
                        .build();
            }
        }

然后:
RetrofitClient.getInstance().create(Api.class).getToken() //获取令牌
RetrofitClient.getInstance().create(Api.class).someMethod() //当我得到Token

这是好方法吗?

只需在 RetrofitClient 或其他视情况添加 SharedPreferences 作为构造函数参数即可

您可以通过以下方式进行:

首先使用单例实例

创建首选项class

Preferences

public class Preferences {

    public static Preferences INSTANCE;
    private final String PREFERENCE_FILE = "my_preferences";
    public final String PREF_TOKEN = "pref_user_token";
    private SharedPreferences mPrefs;
    private SharedPreferences.Editor mEdit;

    private Preferences() {
        Application app = MyApplicationClass.getInstance();
        mPrefs = app.getSharedPreferences(PREFERENCE_FILE, Context.MODE_PRIVATE);
        mEdit = mPrefs.edit();
    }

    // Returns singleton instance
    public static Preferences getInstance() {
        if (INSTANCE == null)
            INSTANCE = new Preferences();
        return INSTANCE;
    }

    public String getToken() {
        return Preferences.getInstance().mPrefs.getString(PREF_TOKEN, "");
    }

    public void saveToken(String value) {
        mEdit.putString(PREF_TOKEN, value);
        mEdit.apply();
    }

}

然后在你的 RetrofitClient class 中改变如下:

RetrofitClient

public class RetrofitClient {

    public static final String BASE_URL = "http://localhost";
    public static Retrofit retrofit = null;

    private RetrofitClient() {
        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(mClient)
                .build();
    }

    OkHttpClient mClient = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request newRequest = chain.request().newBuilder()
                    .addHeader("Authorization", "Bearer" + Preferences.getInstance().getToken())
        }
    })

    public static synchronized Retrofit getInstance() {
        if (retrofit == null) {

            retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create()).build();
        }
        return retrofit;
    }

    public Api getApi() {
        return retrofit.create(Api.class);
    }
}

您可以使用在您的应用程序运行时可用的应用程序上下文。从您的应用中获取 class:

public class MyApp extends Application {
    private static MyApp instance;
    @Override
    public void onCreate() {
    super.onCreate();
    instance = this;
    //other code
}
public static MyApp getInstance() {
    return instance;
}

然后只需使用 MyApp.getInstance() 即可在您需要的地方获取上下文。通过这种方法,您可以实现您之前的想法,并在 RetrofitClient class.

中获得 SharedPreferences

不要忘记将您的应用 class 添加到清单中。

更新: 您只创建了一次改造实例,因此如果您在拥有令牌时创建它 - 您将始终使用它,而应用程序仍然存在。 我认为,好的做法是在拦截器中检查令牌。像这样:

new Interceptor() {
        @Override
        public Response intercept(@NonNull Chain chain) throws IOException {
            Request request = chain.request();
            if (tokenService.token == null) {
                return chain.proceed(request);
            } else {
                return chain.proceed(request.newBuilder().addHeader("Authorization", "Bearer" + tokenService.token).build());
            }
        }
    }

另外,我不知道你的 tokenService 是如何工作的。但请记住,最好始终检查令牌的共享首选项,如果您在注销时清除它。因为您的 tokenService 可能会保留令牌字符串,即使它已在共享首选项中被清除。