SkypeDogg
SkypeDogg

Reputation: 1040

Retrofit2 interceptor, using token only in specific methods

I want to use authorization in Retrofit2. I've choosen interceptor way because almost all methods require authorization, except one where I am geting token for further use with other methods.

My question is: How can I achieve this?

I store my access token in SharedPreferences. My first idea was: "I can retrieve it in my RetrofitClient class and depending if token is null or it has value create suitable Retrofit instance" (with or without adding .client() to it.

Unfortunately it's not that easy because Context is needed to get preferences.

I don't know how to pass it into RetrofitClient class or how to get to it inside.

Here's my 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);
    }
}

My getRequestHeader() is previous method where I was setting timeout.

I want to create instance like this:

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();
            }
        }

And then:
RetrofitClient.getInstance().create(Api.class).getToken() //getting Token
RetrofitClient.getInstance().create(Api.class).someMethod() //when I get Token

Is it good approach?

Upvotes: 0

Views: 1115

Answers (3)

H.Taras
H.Taras

Reputation: 832

You can use application context which is available while your app is live. Get it from your app 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;
}

And then simply use MyApp.getInstance() to get context where you need. With this approach you can achieve what did you think before and get SharedPreferences in RetrofitClient class.

Don't forget to add your app class to manifest.

UPDATE: You are creating your retrofit instance only once, so if you create it when you will have token - you will always use it, while app is alive. I think, good practice is to check for token in your interceptor. Something like this:

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());
            }
        }
    }

Also, I don't know how your tokenService is working. But keep in mind, that the best is to always check in shared preferences for token, if you clear it there when logout. Because your tokenService may keep token string even if it is cleared in shared preferences.

Upvotes: 1

android
android

Reputation: 3090

You can do in following way:

First create a preference class with singleton instance

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();
    }

}

Then change in you RetrofitClient class as below:

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);
    }
}

Upvotes: 0

Antonis Radz
Antonis Radz

Reputation: 3097

Simply add SharedPreferences as constructor parameter in RetrofitClient or other depending on situation

Upvotes: 0

Related Questions