2

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

0

3 Answers 3

1

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

}
Sign up to request clarification or add additional context in comments.

1 Comment

It really helps but it is not the answer. I solved my problem by using a cookieManager. BTW thank you
0

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.

2 Comments

I have the token in my shared preferences. My issue is that in the second request I can get the cookies from the first request. I think I need to pass all the headers from the first request again but by using intercept nothing happens.
Check where you are saving the token. It appears that the server is sending you a new token after your first request. Maybe make sure you only set it once?
0

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

2 Comments

I used this before and checked my request even. Nothing added to the request. .addHeader("Authenticator", prefs.getToken()) something goes wrong here whitout any error I think.
I updated my post base on your suggestion. you can see that my first and second headers are different.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.