I am creating app that consumes REST Api. My API has ability to login/logout in order to access private data. I am creating consumer(client Android app) with Retrofit + Robospice + Jackson.
Everything was okey, but than authorization part came into play.
I need to provide token and other credentials in my request Authorization Header
.
This can be easily done by using RequestInterceptor
. Here is complete tutorial how to use basic Authentication.
Basic Authentication with Retrofit .
It is clear how to implement this. But in my case I also have resources that can be accessed without credentials.
Here is part of my API declared with Retrofit Annotations
public interface MalibuRestApi {
//Doesn't need credentials
@GET("/store/categories")
Category.List categoryList();
//Doesn't need credentials
@GET("/store/categories/{id}/products")
Product.List productList(@Path("id")int categoryId);
// Needs credentials
@POST("/store/users/{id}/logout")
// Needs credentials
User logout(@Path("id") int id,@Body Credentials userCredentials);
// Needs credentials !!!!!!!!!!!!!!!!!!!!
@POST("/store/users/{id}/orders/")
void makeAnOrder(@Path("id") int userId,@Body Order order,Callback<Void> callback);
}
Please have a look on makeAnOrder
method. It uses POST body to pass details about order. So combining credentials and order seems horrible and not efficient, and I won't use it under no circumstances.
It is possible to use interceptor.
builder.setRequestInterceptor(new RequestInterceptor() {
@Override
public void intercept(RequestFacade request) {
if
String token = .... // getting token.
request.addHeader("Accept", "application/json");
request.addHeader("Authorization",token);
}
});
I can filter requests and add Auth headers where I need them according to request URL, but ......
According to the discussion here.
@JakeWharton
The relative URL is not exposed in the request interceptor because it may not be fully resolved yet. A request interceptor has the ability to perform path replacements and append query parameter
There is one possible workaround.
@powerje
I'm not sure how to access the relative URL in RequestInterceptor but the solution I used in a similar situation was to check my UserManager (a global which manages the currently logged in user) to see if a user is logged in, if they are I add the auth header, otherwise I don't.
I have already similar class Session manager that is created in custom Application class, so I assume that it will live until application(linux dalvik/art process) is destroyed.
So it is possible to do something like this.
builder.setRequestInterceptor(new RequestInterceptor() {
@Override
public void intercept(RequestFacade request) {
sessionManager =(SessionProvider) getApplicationContext().getSessionManager();
if(sessionManager.userLoggedIn) {
String token = .... // getting token.
request.addHeader("Accept", "application/json");
request.addHeader("Authorization",token);
}
}
I haven't tested this yet, but it pretends to work.
In this case redundant headers are passed to public resource requests, that don't really require them.
So maybe this can be a sort of solution not a question, but I really need some advice about any other ways (maybe not better) to solve this problem.
I will be grateful for any help.