Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Persisting Server Session using cookie When Making HTTP calls

Server side sessions are stored in database and maintained using cookies. So, every client must come with a valid cookie matching a session in the database.

and on Android side:

DefaultHttpClient client = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
HttpResponse response = client.execute(httppost);

If I am using the same client for all the server calls, the client takes care of these cookies.

But the problem is, when the client is destroyed, because of memory needed by the device, the cookies are lost and any subsequent server calls doesn't work.

Is there a way to make the HttpClient persistent? Or what is the usual way to maintain cookies on android side.

like image 265
Archie.bpgc Avatar asked Oct 01 '13 14:10

Archie.bpgc


People also ask

Is session better than cookie?

Session is safer for storing user data because it can not be modified by the end-user and can only be set on the server-side. Cookies on the other hand can be hijacked because they are just stored on the browser.

What is the difference between Httpsession and cookies?

Cookies and session both store information about the user (to make the HTTP request stateful) but the difference is that cookies store information on the client-side (browser) and sessions store information on the server-side.

How does cookie session work?

Session cookies allow websites to remember users within a website when they move between web pages. These cookies tell the server what pages to show the user so the user doesn't have to remember where they left off or start navigating the site all over again. Therefore, without session cookies, websites have no memory.

What are HTTP sessions and cookies?

In what is certainly one of the most widely accepted, useful hacks in technical history, HTTP was given the means by which state could be tracked throughout the use of an application. That "hack" is where sessions and cookies come into play. Sessions are the way in which web and application servers maintain state.

What is httpurlconnection Cookie Manager in Android?

Android’s HttpURLConnection includes an extensible cookie manager that helps to establish and maintain a long-lived session between client (Android) and server. For best performance, you should call either setFixedLengthStreamingMode (int) when the body length is known in advance… CookieStore can be used for cookie persistence.

What is cookie-based persistence and how does it work?

That technique is called cookie-based persistence. Rather than rely on the SSL/TLS session ID, the load balancer would insert a cookie to uniquely identify the session the first time a client accessed the site and then refer to that cookie in subsequent requests to persist the connection to the appropriate server.

What is the use of custom cookies in Android?

Cookies allow sites to keep track of users. Cookies can thus be used to create a user session layer on top of stateless HTTP. Android’s HttpURLConnection includes an extensible cookie manager that helps to establish and maintain a long-lived session between client (Android) and server.


1 Answers

The "correct" way of doing this is to implement a CookieHandler: http://developer.android.com/reference/java/net/CookieHandler.html

The most basic way of doing this is to extend Application and put this in your applications onCreate():

CookieHandler.setDefault(new CookieManager());

PLEASE NOTE: This will only implement a DEFAULT CookieManger. The default CookieManger will manage cookies for all of your HTTP requests during a specific session of your application. However, it does not have any means of persisting cookies over subsequent uses of the application.

In order to do that, you'll need to write your own cookie manager by implementing CookieStore: http://developer.android.com/reference/java/net/CookieStore.html

Here's an example of a CookieStore implementation i used in an app that is currently in the Google Play store:

package com.touchvision.util;

import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.util.Log;

import com.touchvision.Config;

/*
 * This is a custom cookie storage for the application. This
 * will store all the cookies to the shared preferences so that it persists
 * across application restarts.
 */
public class TvCookieStore implements CookieStore {

    private static final String LOGTAG = "TV-TvCookieStore";

    /*
     * The memory storage of the cookies
     */
    private Map<String, Map<String,String>> mapCookies = new HashMap<String, Map<String,String>>();
    /*
     * The instance of the shared preferences
     */
    private final SharedPreferences sharedPrefs;

    /*
     * @see java.net.CookieStore#add(java.net.URI, java.net.HttpCookie)
     */
    public void add(URI uri, HttpCookie cookie) {

        String domain = cookie.getDomain();     

        // Log.i(LOGTAG, "adding ( " + domain +", " + cookie.toString() );

        Map<String,String> cookies = mapCookies.get(domain);
        if (cookies == null) {
            cookies = new HashMap<String, String>(); 
            mapCookies.put(domain, cookies);
        }
        cookies.put(cookie.getName(), cookie.getValue());

        if (cookie.getName().startsWith("SPRING_SECURITY") && !cookie.getValue().equals("")){
           //  Log.i(LOGTAG, "Saving rememberMeCookie = " + cookie.getValue() );            
            // Update in Shared Preferences
            Editor e = sharedPrefs.edit();       
            e.putString(Config.PREF_SPRING_SECURITY_COOKIE, cookie.toString());       
            e.commit(); // save changes 
        }

    }

   /*
    * Constructor
    * 
    * @param  ctxContext the context of the Activity
    */
    public TvCookieStore(Context ctxContext) {

        // Log.i(LOGTAG, "constructor()");

        sharedPrefs = ctxContext.getSharedPreferences(Config.SHARED_PREF_NAME, Context.MODE_PRIVATE);
    }

    /*
     * @see java.net.CookieStore#get(java.net.URI)
     */
    public List<HttpCookie> get(URI uri) {

        List<HttpCookie> cookieList = new ArrayList<HttpCookie>();

        String domain = uri.getHost(); 

        // Log.i(LOGTAG, "getting ( " + domain +" )" );

        Map<String,String> cookies = mapCookies.get(domain);
        if (cookies == null) {
               cookies = new HashMap<String, String>(); 
               mapCookies.put(domain, cookies);
        }  

        for (Map.Entry<String, String> entry : cookies.entrySet()) {
            cookieList.add(new HttpCookie(entry.getKey(), entry.getValue()));
            // Log.i(LOGTAG, "returning cookie: " + entry.getKey() + "="+ entry.getValue());
        }
        return cookieList; 

    }

    /*
     * @see java.net.CookieStore#removeAll()
     */
    public boolean removeAll() {

        // Log.i(LOGTAG, "removeAll()" );

        mapCookies.clear();
        return true;

    }        

    /*
     * @see java.net.CookieStore#getCookies()
     */
    public List<HttpCookie> getCookies() {

        Log.i(LOGTAG, "getCookies()" );

        Set<String> mapKeys = mapCookies.keySet();

        List<HttpCookie> result = new ArrayList<HttpCookie>();
        for (String key : mapKeys) {
            Map<String,String> cookies =    mapCookies.get(key);
            for (Map.Entry<String, String> entry : cookies.entrySet()) {
                result.add(new HttpCookie(entry.getKey(), entry.getValue()));
                Log.i(LOGTAG, "returning cookie: " + entry.getKey() + "="+ entry.getValue());
            }             
        }

        return result;

    }

    /*
     * @see java.net.CookieStore#getURIs()
     */
    public List<URI> getURIs() {

        Log.i(LOGTAG, "getURIs()" );

        Set<String> keys = mapCookies.keySet();
        List<URI> uris = new ArrayList<URI>(keys.size());
        for (String key : keys){
            URI uri = null;
            try {
                uri = new URI(key);
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
            uris.add(uri);
        }
        return uris;

    }

    /*
     * @see java.net.CookieStore#remove(java.net.URI, java.net.HttpCookie)
     */
    public boolean remove(URI uri, HttpCookie cookie) {

        String domain = cookie.getDomain();     

        Log.i(LOGTAG, "remove( " + domain +", " + cookie.toString() );

        Map<String,String> lstCookies = mapCookies.get(domain);

        if (lstCookies == null)
            return false;

        return lstCookies.remove(cookie.getName()) != null;

    }

}

The above custom CookieStore uses SharedPreferences to persist cookies. You implement the above class the similar to how you would implement the default CookieManager in your application class, but the line would look like this:

CookieHandler.setDefault( new CookieManager( new TvCookieStore(this), CookiePolicy.ACCEPT_ALL));

As you can see, the only Cookie i really cared about persisting was the Spring Security Cookie (we were using Spring Framework on the server side). Your code will obviously be different to account for your specific needs.

Another quick note: I tried countless times to do what you're doing and handle the persistence of cookies within my http client class. It was nothing but headaches. Give this strategy a shot.

like image 152
SBerg413 Avatar answered Sep 19 '22 15:09

SBerg413