How to implement cookie handling on Android using OkHttp? - android

Using OkHttp by Square https://github.com/square/okhttp, how can I:
Retrieve a cookie returned from the server
Store the cookie for upcoming requests
Use the stored cookie in subsequent requests
Update the cookie returned by the subsequent request
Ideally the cookie would be stored, resent and updated automatically with every request.

For OkHttp3, a simple accept-all, non-persistent CookieJar implementation can be as follows:
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();
#Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url, cookies);
}
#Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url);
return cookies != null ? cookies : new ArrayList<Cookie>();
}
})
.build();
Or if you prefer to use java.net.CookieManager, include okhttp-urlconnection in your project, which contains JavaNetCookieJar, a wrapper class that delegates to java.net.CookieHandler:
dependencies {
compile "com.squareup.okhttp3:okhttp:3.0.0"
compile "com.squareup.okhttp3:okhttp-urlconnection:3.0.0"
}
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new JavaNetCookieJar(cookieManager))
.build();

For OkHttp 3 (or maybe newer)
See hidro's answer
For OkHttp 2.x (or maybe older)
You can pass a CookieHandler to your OkHttpClient instance. You can use the CookieManager implementation from java.net or you could implement your own if you want. Choose the policy that works best for your needs.
OkHttpClient client = new OkHttpClient();
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
client.setCookieHandler(cookieManager);
OkHttp will save cookies received from Responses into the CookieHandler and read from it when sending requests. It will do so for matching request/response URIs.

I needed to share the default Cookie Jar (CookieManager.getInstance()) so this seemed to work ok for me.
return new CookieJar() {
#Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
CookieManager cookieManager = CookieManager.getInstance();
for (Cookie cookie : cookies) {
cookieManager.setCookie(url.toString(), cookie.toString());
}
}
#Override
public List<Cookie> loadForRequest(HttpUrl url) {
CookieManager cookieManager = CookieManager.getInstance();
List<Cookie> cookies = new ArrayList<>();
if (cookieManager.getCookie(url.toString()) != null) {
String[] splitCookies = cookieManager.getCookie(url.toString()).split("[,;]");
for (int i=0; i<splitCookies.length; i++) {
cookies.add(Cookie.parse(url, splitCookies[i].trim()));
}
}
return cookies;
}
};

Related

how to handle cookies for okhttpclient requests

I am sending a request to a website's webpage's url using OkHttpClient and storing the cookie it gives by the following method which I got from stackoverflow only.
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(this));
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.build();
Request request = new Request.Builder()
.url("www.example.com/homePage")
.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0")
.build();
It is necessary to store the cookie otherwise the website redirects the request to a timeout page.
Then, I see the html of the page to check whether I reached the correct URL.
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
textView.setText("Failed to get response");
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
//String myResponse contains the html of the webpage
final String myResponse = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(myResponse);
}
});
}
}
});
Now, I make another Request variable in a similar fashion to the URL "www.example.com/loginPage" and try to see the html but it redirects me to the timeout page because the request is made without sending the cookie which I got from the homePage.
So, in short, how can I get a cookie from "www.example.com/cookieProviderPage" and store it and then use that cookie for all further requests to all pages of that website. Pages of that website have different urls like "www.example.com/cookieRequiredPage1", "www.example.com/cookieRequiredPage2" etc.
P.S. - I have checked many stackoverflow questions related to cookies but I am unable to implement the them specifically to my case.
Cookies added with Command
new OkHttpClient.Builder()
.cookieJar(cookieJar)
are loaded depending on the CookieJar.loadForRequest method. You must check, how your implementation of the interface CookieJar implemented the loadForRequest method. If cookies are just loaded for exact the same url the cookies originally come from, you have the error.
If the cookies come from "www.example.com/cookieProviderPage" and you want to supply the cookies for the request "www.example.com/loginPage", your CookieJar implementation may only supply the cookies to requests with the url "www.example.com/cookieProviderPage".
This is for example the case, if Cookie.matches is used to the get the cookies for the request. Cookie.matches compares domain name and path of the url.

Add cookie to client request OkHttp

So i started using Okhttp 3 and most of the examples on the web talk about older versions
I need to add a cookie to the OkHttp client requests, how is it done with OkHttp 3?
In my case i simply want to statically add it to client calls without receiving it from the server
There are 2 ways you can do this:
OkHttpClient client = new OkHttpClient().newBuilder()
.cookieJar(new CookieJar() {
#Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
}
#Override
public List<Cookie> loadForRequest(HttpUrl url) {
Arrays.asList(createNonPersistentCookie());
}
})
.build();
// ...
public static Cookie createNonPersistentCookie() {
return new Cookie.Builder()
.domain("publicobject.com")
.path("/")
.name("cookie-name")
.value("cookie-value")
.httpOnly()
.secure()
.build();
}
or simply
OkHttpClient client = new OkHttpClient().newBuilder()
.addInterceptor(chain -> {
final Request original = chain.request();
final Request authorized = original.newBuilder()
.addHeader("Cookie", "cookie-name=cookie-value")
.build();
return chain.proceed(authorized);
})
.build();
I have a feeling that the second suggestion is what you need.
You can find here a working example.
If you need to set a cookie for a single request you can just add the header:
Request request = new Request.Builder()
.addHeader("Cookie", "yourcookie")
.url("http://yoursite.com")
.build();
Otherwise, if you want to read cookies returned by the server and attach them to other requests you will need a CookieJar. For Android you can use the PersistentCookieJar library which handles cookies properly and also saves them in the shared preferences:
ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context));
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.build();
I had the same needs, I made my own library.
You can force set cookies like this with OkHttp3CookieHelper on https://github.com/riversun/okhttp3-cookie-helper .
String url = "https://example.com/webapi";
OkHttp3CookieHelper cookieHelper = new OkHttp3CookieHelper();
cookieHelper.setCookie(url, "cookie_name", "cookie_value");
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(cookieHelper.cookieJar())
.build();
Request request = new Request.Builder()
.url(url)
.build();
Gradle
compile 'org.riversun:okhttp3-cookie-helper:1.0.0'
Maven
<dependency>
<groupId>org.riversun</groupId>
<artifactId>okhttp3-cookie-helper</artifactId>
<version>1.0.0</version>
</dependency>
I think a better way to do this is by adding the cookie to the cookieJar. OkHttp will then automatically add the cookies to the request with an interceptor: https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/internal/http/BridgeInterceptor.java
cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
JavaNetCookieJar cookieJar = new JavaNetCookieJar(cookieManager);
// add cookies to cookiejar
cookieJar.saveFromResponse("Cookie", listOfCookiesToAdd);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.cookieJar(cookieJar)
I didn't actually try this code, but it should work.

How to prevent Retrofit from clearing my cookies

I get a cookie from my backend API that allows me to authenticate all subsequent user requests.
I'm using retrofit, and I can't get it to keep the session key between requests. I want to know how to configure retrofit so that it keeps the session key around and uses it for all future requests:
public class ApiClient{
private static final String API_URL = "http://192.168.1.25:8080";
private static RestAppApiInterface sRestAppService;
public static RestAppApiInterface getRestAppApiClient() {
if (sRestAppService == null) {
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(cookieManager);
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(API_URL)
.build();
sRestAppService = restAdapter.create(RestAppApiInterface.class);
}
return sRestAppService;
}
}
You need to set a Cookie persistent Client.
Since you're using Android and retrofit I suggest using OKHttp wich is better supported by retrofit and Android thread safe, the way to this is the following
//First create a new okhttpClient (this is okhttpnative)
OkHttpClient client = new OkHttpClient(); //create OKHTTPClient
//create a cookieManager so your client can be cookie persistant
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
client.setCookieHandler(cookieManager); //finally set the cookie handler on client
//OkClient is retrofit default client, ofcourse since is based on OkHttClient
//you can decorate your existing okhttpclient with retrofit's okClient
OkClient serviceClient = new OkClient(client);
//finally set in your adapter
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("Some eNdpoint")
.setClient(serviceClient)
.build();
The point of using Okhttp instead of the defaultHttpClient(by apache) is that okhttp is threadsafe for android and better supported by retrofit.
Remembar that if you create another adapter you will need to set the same client, perhaps if you implement singleton on the client instance you will use the same one for all your requests, keeping in the same context
I hope this helps,best
If you use Retrofit 2 you can add the library:
compile "com.squareup.okhttp3:okhttp-urlconnection:3.2.0"
then use the following code to manage cookies when you create your OkHttp client:
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.cookieJar(new JavaNetCookieJar(cookieManager));

LoopJ AndroidAsyncHttp and Persistent cookie store

Inside my service I run this code:
public class MainService extends Service {
....
....
CookieManager mCookieManager = CookieManager.getInstance();
CookieSyncManager mCookieSyncManager = CookieSyncManager.createInstance(mContext);
if (mCookieSyncManager != null) {
mCookieSyncManager.sync();
}
AsyncHttpClient myClient = new AsyncHttpClient();
PersistentCookieStore myCookieStore = new PersistentCookieStore(mContext);
myClient.setCookieStore(myCookieStore);
myClient.setUserAgent("my service");
myClient.get("http://example.com/mypage/", new AsyncHttpResponseHandler() {
...
}
...
...
}
When I check my webserver logs, I can see cookies exists in request headers.
But these cookies are old cookies.
I also run this AndroidAsyncHttp code from an Activity. Same old cookies are sent.
But when I print out current cookies in my WebView, I see new cookies.
How can I send WebView's cookies with AndroidAsyncHttp ?
Clear cookie before set the cookie
myCookieStore.clear();
In my experience I don't need that CookieManager.
I only use this.
AsyncHttpClient myClient = new AsyncHttpClient();
PersistentCookieStore myCookieStore = new PersistentCookieStore(mContext);
// clear cookie to make the fresh cookie, to ensure the newest cookie is being send
myCookieStore.clear();
// set the new cookie
myClient.setCookieStore(myCookieStore);
myClient.get("http://example.com/mypage/", new AsyncHttpResponseHandler() {
...
}

Android server-client application session issue

I am developing server client application on android and i am using session on server side of application but sometimes i lost my session on server.
Ps: i use https connection on server.
I am using these to hold session:
I am using single instance DefaultHttpClient and use it for all http requests.
I use only httpPost method
I use only https certificate:
schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
I save my cookies after all http requests:
private void createSessionCookie(){
List<Cookie> cookies = httpclient.getCookieStore().getCookies();
if (! cookies.isEmpty()){
CookieSyncManager.createInstance(ctx);
CookieManager cookieManager = CookieManager.getInstance();
//sync all the cookies in the httpclient with the webview by generating cookie string
for (Cookie cookie : cookies){
Cookie sessionInfo = cookie;
String cookieString = sessionInfo.getName() + "=" + sessionInfo.getValue() + "; domain=" + sessionInfo.getDomain();
cookieManager.setCookie(UrlConstants.SERVICE_PRE_URL, cookieString);
CookieSyncManager.getInstance().sync();
}
}
}
Even though i am doing these, i lose session.
Please help me to solve this problem,
Thanks for any advice
Best Regards.
You should not do anything with cookies manually, just create static CookieStore somewhere, assign it to the HttpContext, and use that context in your requests. Cookies will be saved and restored automagically.
These are your class members:
private static CookieStore cookieStore = new BasicCookieStore();
private HttpClient httpclient = new DefaultHttpClient();
private HttpPost post = new HttpPost("your url here");
And this part goes into the member function, which does the request:
HttpContext ctx = new BasicHttpContext();
ctx.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpResponse result = httpclient.execute(post,ctx);

Categories

Resources