AEF
AEF

Reputation: 157

token authentication using retrofit

The scenario is that I have a login activity that sends username and passwords to the php-rest-api and if the response is ok it will show a new activity (here it is a test activity).

Then, in the new activity, with a token that I got from the login procedure, I can query the database by retrofit.

The problem is that I need to save cookies from the login attempt to use it in my next request.
I am using retrofit:2.2.0 and I read How to retrieve cookies in Retrofit? and Retrofit keeps forgeting my cookies :( Android and I checked all the possible solution.

My app works, no error happens, but the header fields values in my first and second activity are different.

This is my retrofit client:

public class RetrofitClient {

    private static String BASE_URL = "http://192.168.0.100/rest/main.php/";
    private static Retrofit retrofit = null;

    public static Retrofit getRetroftInstance() {
        if (retrofit == null) {

            OkHttpClient cl = new OkHttpClient().newBuilder().addInterceptor(new AuthInterceptor()).build();

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

        return retrofit;
    }}

This is authenticationinceptor:
public class AuthInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); request = request.newBuilder() .addHeader("X-XSRF-TOKEN", ServiceSharedPrefs.getInstance().getToken()) .build(); Response response = chain.proceed(request); return response; } }

This is my login procedure:

private void loginProcedure(final String username, final String password) {
    //Creat a user base on the user input
    UserDB user = new UserDB(username, password);
    //send data to the api and get response
    Call<ApiDB> call = retrofitInterfaceObject.checkCredentials(user);
    call.enqueue(new Callback<ApiDB>() {
        @Override
        public void onResponse(Call<ApiDB> call, Response<ApiDB> response) {
            //Unauthorized handling
            if (response.code() == 401) {
                Toast.makeText(LoginActivity.this, "in 401", Toast.LENGTH_SHORT).show();
                ServiceDialog
                        .getInstance()
                        .CreateDialog(LoginActivity.this,
                                String.valueOf(response.code())
                                        + LoginActivity.this.getString(R.string.login_unauthorized_error_title)
                                , LoginActivity.this.getString(R.string.login_unauthorized_error_message)
                                , LoginActivity.this.getString(R.string.Generall_Ok_Text), null, null, null, false, false);
            }
            //Handling the 200 response : 2 possibility
            else if (response.code() == 200) {
                //if login ok
                if (response.body().getLogin() != null) {
                    if (response.body().getLogin().contains("yes")) {
                        for(int i =0 ;i < response.headers().size();i++){
                            Log.v("mmmm login header:"+i,response.headers().name(i));
                        }
                        sharedPrefs.setToken(response.headers().get("X-XSRF-TOKEN"));
                        sharedPrefs.saveData(username, password);
                        LoginActivity.this.startActivity(new Intent(LoginActivity.this, test_check.class));
                    }

                }
                //if login not ok
                else if (response.body().getError().contains("Error in authentication!")) {
                    ServiceDialog
                            .getInstance()
                            .CreateDialog(LoginActivity.this, LoginActivity.this.getString(R.string.login_credentials_error_title)
                                    , LoginActivity.this.getString(R.string.login_credentials_error_message)
                                    , LoginActivity.this.getString(R.string.Generall_Ok_Text), null, null, null, false, false);
                }
            }
            //Handle other situations
            else {
                ServiceDialog
                        .getInstance()
                        .CreateDialog(LoginActivity.this, response.code() + " : " + LoginActivity.this.getString(R.string.login_null_error_title)
                                , LoginActivity.this.getString(R.string.login_null_error_message)
                                , LoginActivity.this.getString(R.string.Generall_Ok_Text), null, null, null, false, false);
            }
        }

        @Override
        public void onFailure(Call<ApiDB> call, Throwable t) {
            ServiceDialog.getInstance().CreateDialog(LoginActivity.this, LoginActivity.this.getString(R.string.login_null_error_title)
                    , t.getMessage() + "\n" + t.getLocalizedMessage(), LoginActivity.this.getString(R.string.Generall_Ok_Text),
                    null, null, null, true, true);
        }
    });

This is my test activity:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test_check);
    final TextView t = (TextView) findViewById(R.id.txviewtest);

    //t.setText(ping("192.168.0.100"));


    Call<UserDB> call = this.ret.get1(ServiceSharedPrefs.getInstance().getToken());
    call.enqueue(new Callback<UserDB>() {
        @Override
        public void onResponse(Call<UserDB> call, Response<UserDB> response) {
            for(int i =0 ;i < response.headers().size();i++){
                Log.v("mmmm check header:"+i,response.headers().name(i));
            }
            t.append(ServiceSharedPrefs.getInstance().getToken());
            t.append("\n");
            t.append(String.valueOf(response.code()));
            t.append("\n");
            t.append(response.headers().toString());
            t.append("\n");

            t.append(response.body().toString());

        }
        @Override
        public void onFailure(Call<UserDB> call, Throwable t) {
            ServiceDialog.getInstance().CreateDialog(test_check.this, t.getMessage(),
                    null, getString(R.string.Generall_Ok_Text), null, null, null, true, true);
        }
    });

my first header :

login header:0: Date:Thu, 18 May 2017 08:10:50 GMT login header:1: Server:Apache/2.4.23 (Win64) PHP/5.6.25 login header:2: X-Powered-By:PHP/5.6.25 login header:3: Set-Cookie:XSRF-TOKEN=N18743296; path=/ login header:4: Expires:Thu, 19 Nov 1981 08:52:00 GMT login header:5: Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0 login header:6: Pragma:no-cache login header:7: Set-Cookie:XSRF-TOKEN=N18743296; path=/ login header:8: Set-Cookie:XSRF-TOKEN=N18743296; path=/ login header:9: X-XSRF-TOKEN:N18743296 login header:10: Content-Length:15 login header:11: Keep-Alive:timeout=5, max=100 login header:12: Connection:Keep-Alive login header:13: Content-Type:text/html; charset=UTF-8

my second header :

second header:0: Date:Thu, 18 May 2017 08:10:50 GMT second header:1: Server:Apache/2.4.23 (Win64) PHP/5.6.25 second header:2: X-Powered-By:PHP/5.6.25 second header:3: Set-Cookie:PHPSESSID=8ol17tht32l24fblejn2mjm9d4; path=/; HttpOnly second header:4: Expires:Thu, 19 Nov 1981 08:52:00 GMT second header:5: Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0 second header:6: Pragma:no-cache second header:7: Content-Length:154 second header:8: Keep-Alive:timeout=5, max=99 second header:9: Connection:Keep-Alive second header:10: Content-Type:application/json; charset=utf-8

Upvotes: 2

Views: 13414

Answers (3)

Piyush Patel
Piyush Patel

Reputation: 381

Hello try this snippet one will receive cookies when you login and one will set cookies after you login and have token

public class RetrofitClient {

    private static String BASE_URL = "http://192.168.0.100/rest/main.php/";
    private static Retrofit retrofit = null;

    public static Retrofit getRetroftInstance() {
        if (retrofit == null) {

            OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
            httpClient.addNetworkInterceptor(new SessionRequestInterceptor());
            httpClient.addNetworkInterceptor(new ReceivedCookiesInterceptor());

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

        return retrofit;
    }}

public class ReceivedCookiesInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Response originalResponse = chain.proceed(chain.request());

        if (!originalResponse.headers("Set-Cookie").isEmpty()) {
            HashSet<String> cookies = new HashSet<>();
            for (String header : originalResponse.headers("Set-Cookie")) {
                cookies.add(header);
                if(header.startsWith("XSRF-TOKEN")) {
                    String newCookie[]=header.split(";");
                    System.out.println("newCookie Length: "+newCookie.length);
                    for(String ss:newCookie) {
                        if(ss.startsWith("XSRF-TOKEN")) {
                            System.out.println("Cookies ss: " + ss);
                            sharedPrefs.setToken(ss);
                        }
                    }
                }
            }
        }
        return originalResponse;
    }
}

public class SessionRequestInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();

        Request.Builder request = original.newBuilder();

        request.header("Cookie",ServiceSharedPrefs.getInstance().getToken()));

        request.method(original.method(), original.body());

        return chain.proceed(request.build());
    }

}

Upvotes: 1

Arun Shankar
Arun Shankar

Reputation: 2295

Save the token that you get in the first activity into the Sharedpreferences and use it like shown below. The code inside * * at two places should solve your problem

***
public class AuthInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain)
            throws IOException {
        Request request = chain.request();
        if(prefs!=null && prefs.hasToken()){//essentially checking if the prefs has a non null token
        request = request.newBuilder()
                .addHeader("Authenticator", prefs.getToken())
                .build();
        }
        Response response = chain.proceed(request);
        return response;
    }
}
***

retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                ***
                .addInterceptor(new AuthInterceptor())
               //this is nota valid function.first we should ccreate a 
               //OkHttp client and add this intercept to it.
                ***
               // .client(client)
                .build();

Upvotes: 0

RestingRobot
RestingRobot

Reputation: 2978

Have you tried saving the token in SharedPreferences? I find its much easier to save the token here, and access it when you are ready to build your request. I use an intercepter and it works really well.

Upvotes: 0

Related Questions