Authorization headers with Retrofit + Robospice + Jackson - android

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.

Related

Android clean architecture implement refresh token

I have an application that is implemented with clean architecture with MVVM pattern. In this app we need a refresh token request that is needed in all the app features. When a refresh token is success then call the last request again. What is the best way to implement this?
I have two idea:
1 - Implement it in every feature and use it. So if I have three features in my app I will implement it three time.
2 - Implemented globally
I know the first idea but I can't figure out how to do the second one which I think is better.
I use retrofit for networking . The structure is : data , domain , presentation .
With Retrofit you can create a custom Authenticator which will trigger when a request was denied because of an authentication error (typically 401, the documentation for the Authenticator interface explains more). In your authenticator you can retrieve a new token and automatically create a new request with the new token.
An authenticator will be something like:
class Authenticator : okhttp3.Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
// Make your network request to retrieve a new token
val newToken = ...
// Check if a new token was retrieved
val retrievedNewToken: Boolean = true
return if (retrievedNewToken) {
response.request().newBuilder()
.header("Authorization", "token-value-here")
.build()
} else {
// Couldn't get new token, abort the request
null
}
}
}
And use it in your OkHttpClient:
val client = OkHttpClient.Builder()
.authenticator(Authenticator())
.build()
This is a fairly general answer as I can't provide any specific way of doing it since I don't know the rest of your code, but that's the gist of it. Something to be aware of is that you might need to handle if a new token request is already happening, as it will potentially make multiple requests for a new token if you make several requests right after each other that all are denied.

Authentication role - Clean Architecture

Lately I have been facing a problem that I wasn't able to came out with a solution, I am building an android application following the Clean Architecture and everything was going fine until I had to think about the authentication role.
I have this structure (layers) on my app:
[ui](activities and fragments) -> [presentation](view models) -> [domain](use case) -> data -> [remote, cache, database].
Now, let's suppose that I want to log in into my app, first I'll go through the login screen and put users credentials, after that I'll call the LoginViewModel and then the LoginUseCase passing the email and password. In its turn, the use case will call the repository, let's say, authenticate and then I'll make a request to the backend with the credentials, if everything's ok then I'll receive back a token that I should store in some fashion, the problem start here, I've created a interceptor that is responsible to get the token from the header, but I have to save it and for that I need to access the shared preferences, is correct to have access to it inside my interceptor? And in every request I had to send it to my backend, what's the best approach ?
I also saw this tutorial https://medium.com/#tsaha.cse/advanced-retrofit2-part-2-authorization-handling-ea1431cb86be but I think that it's not correct to have access to database inside your application class, am I wrong?
Thank you all for reading this, I'm struggling to find out the best approach, so any help are welcome.
it's not really related to CleanArchitecture. Here're answers for your questions:
I have to save it and for that I need to access the shared preferences, is correct to have access to it inside my interceptor?
-> Yes, you should save it to SharedPreferences, but you should not access SharedPreferences inside your interceptor. You should make your interceptor Singleton and create a new setHeaderToken(String token) function in your interceptor. After authorizing, you can set header token to your interceptor. Something like:
class MyInterceptor{
String token = null;
public void setHeaderToken(String token){
//do set...
};
#Override
public Response intercept(Chain chain) throws IOException {
if(token == null) //do nothing
else // do add header
}
}
// add the singleton Interceptor to your OkHttp Client Builder and use it.
You should not connect Application class with your database directly. You should use a domain layer to do so instead.

get and post method in android volley request

I'm confused about post and get request in android volley.
Can you explain me their differences?
And can I use post method with no Param to get a JSON from URL?
Their difference is in functions defined in server.
In simple words, With a GET method, you are sending your data via the URL. While, with A POST method, data is embedded in the form object and sent directly from your browser to the server. ... We usually use GET to identify and dynamically render pages and POST to send form data but it's not always the case.
and answer of your second question is yes you can but that's not a good idea get would be better for that. here is a example of how you can send requests using Volley Library
StringRequest request = new StringRequest(Request.Method.POST, "www.example.com", new Response.Listener<String>() {
#Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> parameters = new HashMap<>();
return parameters;
}
#Override
public String getBodyContentType() {
return "application/x-www-form-urlencoded; charset=UTF-8";
}
};
AppController.getInstance().addToRequestQueue(request, tag);
Are you working on server or server is handled by someone else?
In general, person who works on server decides the method.
Like if you work on JAVA server, then say an API end point is https://sample.api.someurl.com/userInfo/
TO maintain some consistency server programmer may use GET method to get userInfo and he may use POST method to update user info and he may use DELETE method to delete the existing user info.
In this example, your API end point remains same but the request method decides how that end point will behave.
In other example, to save time, a server developer may redirect all the requests to one method and handle it there, so no matter you call GET, POST or DELETE API will return same response.
So yes, Its not Android or UI developer who decides the Method alone, Major role of deciding which method to use is decided by server programmer.
P.S. If you are working on server too, then good practice is to use GET to get the info, POST method to update or add the info and DELETE to remove the info.

Android Retrofit 2, differences between addInterceptor & addNetworkInterceptor for editing responses

I've been trying to implement an interceptor ( OkHttp 3.2 & Retrofit 2 ) for editing the JSON response before is returned as response. The server we request data returns different data dependes on success or error and that makes difficult to map the objects.
I was trying to do it by adding the interceptor to Retrofit as a NetworkInterceptor, however the string returned had no format.
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
try {
final String responseString = new String(response.body().bytes() );
LOGD("OkHttp-NET-Interceptor", "Response: " + responseString);
String newResponseString = editResponse( responseString );
LOGD("OkHttp-NET-Interceptor", "Response edited: " + newResponseString);
return response.newBuilder()
.body(ResponseBody.create(response.body().contentType(), newResponseString))
.build();
}catch (Exception ex){
return response;
}
}
responseString had a string without any understandable format.
After changing to the normal interceptor, the string had format a it was able to convert to JSONObject.
Could tell me someone which are the differences between the responses?
why this line new String(response.body().bytes() ); return different content?
The differences are in the names. NetworkInterceptor hooks in at the network level and is an ideal place to put retry logic and anything that doesn't rely on the actual content of the response.
If what you do depends on the contents of the response (like in your case), using a ApplicationInterceptor is more useful, as it gives you the response after it's been processed by any other moving parts you may have such as a JSON deserializer. Otherwise you would have to implement the JSON deserializing yourself inside the NetworkInterceptor which doesn't make much sense considering it's done for you by Retrofit.
Clarification
Square have this useful diagram on their wiki that shows where each type of interceptor sits
Thus, the reason you receive a readable string in the ApplicationInterceptor is because Square are trying to de-couple the purposes of the two interceptor types. They don't think you should be making any application dependent decisions in the NetworkInterceptor, and so they don't provide an easy way for you to access the response string. It is possible to get ahold of, but like I said, they don't want you to make decisions that depend on the content of the response - rather, they want you to make decisions based or the network state, or headers etc.
The ApplicationInterceptor is where they want you to make decisions dependent upon the contents of the response, so they provide easier methods to access the content of the response so that you can make informed decisions to retry, or as they detail in their wiki, rewrite responses (which I believe is what you're trying to do).
According to #square:
Each interceptor chain has relative merits.
Application interceptors
Don’t need to worry about intermediate responses like redirects and retries.
Are always invoked once, even if the HTTP response is served from the cache.
Observe the application’s original intent. Unconcerned with OkHttp-injected headers like If-None-Match.
Permitted to short-circuit and not call Chain.proceed().
Permitted to retry and make multiple calls to Chain.proceed().
Can adjust Call timeouts using withConnectTimeout, withReadTimeout, withWriteTimeout.
Network Interceptors
Able to operate on intermediate responses like redirects and retries.
Not invoked for cached responses that short-circuit the network.
Observe the data just as it will be transmitted over the network.
Access to the Connection that carries the request.

Retrofit/Robospice: get response headers from successful request?

I am using Retrofit/Robospice to make api calls in an app I've built, with a RetrofitGsonSpiceService. All responses are converted into POJOs using a GSON converter, however there is some information I need to retrieve from the response header. I cannot find any means to get the headers (I can only get the headers if the request is unsuccessful because the raw response is sent in the error object!) how can I intercept the response to grab the headers before it is converted?
It took me a few minutes to figure out exactly what #mato was suggesting in his answer. Here's a concrete example of how to replace the OkClient that comes with Retrofit in order to intercept the response headers.
public class InterceptingOkClient extends OkClient
{
public InterceptingOkClient()
{
}
public InterceptingOkClient(OkHttpClient client)
{
super(client);
}
#Override
public Response execute(Request request) throws IOException
{
Response response = super.execute(request);
for (Header header : response.getHeaders())
{
// do something with header
}
return response;
}
}
You then pass an instance of your custom client to the RestAdapter.Builder:
RestAdapter restAdapter = new RestAdapter.Builder()
.setClient(new InterceptingOkClient())
....
.build();
RoboSpice was designed in a way it doesn't know anything about the HTTP client you end up using in your app. That being said, you should get the response headers from the HTTP client. As Retrofit may use Apache, OkHttp or the default Android HTTP client, you should take a look and see which client you are currently using. Take into account that Retrofit chooses the HTTP client based on certain things (please refer to the Retrofit documentation, or dig into the code, you will find it), unless you manually specify it.
Retrofit defines an interface for clients called Client. If you take a look at the source code, you will see that three classes implement this interface: ApacheClient, OkClient and UrlConnectionClient. Depending on which of them you want to use, extend from one of those, and try to hook into the code that is executed when a response comes back, so that you can get the headers from it.
Once you do that, you have to set your custom Client to Retrofit.

Categories

Resources