Maintaining session in android ( application stay authenticated on the server side) - android

I am building a login application in android in which i am hitting a url(with username and password) upto that part it works fine but after that whenever I am hitting a url(once the user is authenticated) , it return nothing(i.e. a error message like please login first). However it works fine in very similar iphone app and on browser.
I got somewhere that it is the error of phpSessionId(i.e. the session is destroyed for further request) and If we want our Android application to stay authenticated on the server side we need to fetch that id after the first connection and then send it in the headers of all our subsequent requests.
But the problem is that I am unable to get the sessionId from header of the first connection and sending it with further request along with the header.
Please give me some codes or links to complete the task properly.
Thanks.

Finally I solved the issue of session handling in Android.
Android cant handle the session itself(which a simple browser can) so we have to handle it explicitly.
I changed the code for http connection a bit.
Created an instance of DefaultHttpClient in the first Activity when connection established.
public static DefaultHttpClient httpClient;
For the first time connection,I did the following:
URL url=new URL(urlToHit);
LoginScreen.httpClient = new DefaultHttpClient(); //LoginScreen is the name of the current Activity
HttpPost httppost = new HttpPost(url.toString());
HttpResponse response = LoginScreen.httpClient.execute(httppost);
xr.parse(new InputSource(url.openStream())); //SAX parsing
Now for all further connections I used the same httpClient
For example in the next activity:
URL url=new URL(urlToHit);
HttpPost httppost = new HttpPost(url.toString());
HttpResponse response = LoginScreen.httpClient.execute(httppost);
// Log.v("response code",""+response.getStatusLine().getStatusCode());
// Get hold of the response entity
HttpEntity entity = response.getEntity();
InputStream instream = null;
if (entity != null) {
instream = entity.getContent();
}
xr.parse(new InputSource(instream)); //SAX parsing
Hope this will help you all too to solve session issue in Android.

The best idea is to put all the function that your server do in on unique class which is going to be call by the tasks which want to connect. I call this class WebServiceManager. This class have exactly the same method than the server.
As you want an unique session do :
private static WebServiceManager wsm = null;
public static WebServiceManager getInstance() {
if (wsm == null) {
wsm = new WebServiceManager();
}
return wsm;
}
private final HttpClient httpClient;
private WebServiceManager() {
httpClient=new DefaultHttpClient();
}
and then you call the method of your instance of webServiceManager to use always the same session. :)

My problem was that i login first and saved the returned session in userpreferences.
After that the POST call to set a record said
"Error ,Cannot authenticate the User"
So i added
post.setHeader("oAuth-Token", UserPreferences.ACCESS_TOKEN);
the whole thing looks like this.
HttpPost post=new HttpPost(URL );
post.setHeader("oAuth-Token", UserPreferences.ACCESS_TOKEN);
.
.
and It solved the problem.

I wrote a post about it a while back on coderwall
It uses the HttpRequestInterceptor and HttpResponseInterceptor classes which are perfect for that kind of scenario.
Here is an example:
public class HTTPClients {
private static DefaultHttpClient _defaultClient;
private static String session_id;
private static HTTPClients _me;
private HTTPClients() {
}
public static DefaultHttpClient getDefaultHttpClient(){
if ( _defaultClient == null ) {
_defaultClient = new DefaultHttpClient();
_me = new HTTPClients();
_defaultClient.addResponseInterceptor(_me.new SessionKeeper());
_defaultClient.addRequestInterceptor(_me.new SessionAdder());
}
return _defaultClient;
}
private class SessionAdder implements HttpRequestInterceptor {
#Override
public void process(HttpRequest request, HttpContext context)
throws HttpException, IOException {
if ( session_id != null ) {
request.setHeader("Cookie", session_id);
}
}
}
private class SessionKeeper implements HttpResponseInterceptor {
#Override
public void process(HttpResponse response, HttpContext context)
throws HttpException, IOException {
Header[] headers = response.getHeaders("Set-Cookie");
if ( headers != null && headers.length == 1 ){
session_id = headers[0].getValue();
}
}
}
}

Here is an another implementation using Volley library ... a very useful hint from https://stackoverflow.com/a/36496607/3099185
CustomRequest jsonObjReq = new CustomRequest(Request.Method.GET,
url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, response.toString());
}
}, new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_SHORT).show();
// hide the progress dialog
}
});
Custom request class
import android.util.Log;
import com.android.volley.AuthFailureError;
import com.android.volley.Response;
import com.android.volley.toolbox.JsonObjectRequest;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class CustomRequest extends JsonObjectRequest {
private String session_id = "";
public CustomRequest(int method, String url, JSONObject jsonRequest,
Response.Listener listener, Response.ErrorListener errorListener) {
super(method, url, jsonRequest, listener, errorListener);
}
public CustomRequest(int method, String url, JSONObject jsonRequest, String session_id,
Response.Listener listener, Response.ErrorListener errorListener) {
super(method, url, jsonRequest, listener, errorListener);
this.session_id = session_id;
}
#Override
public Map getHeaders() throws AuthFailureError {
Map headers = new HashMap();
Log.d(TAG, " -> session_id = " + session_id);
if(!(session_id.equals(""))) {
headers.put("Cookie", this.session_id);
}
return headers;
}
}
Simple way of implementing volley using singleton pattern
http://arnab.ch/blog/2013/08/asynchronous-http-requests-in-android-using-volley/
Remember to initialize mRequestQueue in onCreate() to avoid unexpected null pointer exception
#Override
public void onCreate() {
super.onCreate();
// initialize the singleton
sInstance = this;
mRequestQueue = Volley.newRequestQueue(this);
}
Hope this help too ... ! :)

Related

AsyncHttpClient POST params become null on server

I am writing method to insert a new record to DB from android.
On client (android studio), I use AsyncHttpClient POST:
JSONObject params = new JSONObject();
try {
params.put("idOrd", idOrd);
params.put("idLan", aIdLan);
params.put("dbIP", dbIP);
params.put("dbName", dbName);
params.put("dbUsername", dbUsername);
params.put("dbPassword", Utility.dbEncrypt(dbPassword));
wsEditMaster(params);
} catch (JSONException | UnsupportedEncodingException e) {
e.printStackTrace();
}
public void wsEditMaster(final JSONObject params) throws UnsupportedEncodingException {
ByteArrayEntity entity = new ByteArrayEntity(params.toString().getBytes("UTF-8"));
entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded"));
client.post(this, "http://" + serverIP + "/DHD/general/editorder", entity, "application/x-www-form-urlencoded", new AsyncHttpResponseHandler() {
And on server (eclipse):
// HTTP Post Method
#POST
// Path: http://localhost/<appln-folder-name>/general/editorder
#Path("/editorder")
// Produces JSON as response
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
// Query parameters are parameters:
public String editOrder(#FormParam("idOrd") String idOrd,
#FormParam("idLan") String idLan, #FormParam("dbIP") String dbIP,
#FormParam("dbName") String dbName,
#FormParam("dbUsername") String dbUsername,
#FormParam("dbPassword") String dbPassword) throws Exception {
String response = "";
if (DBConnection.editOrder(idOrd, idLan, dbIP, dbName, dbUsername, dbPassword)) {
response = Utility.constructJSON("editOrder", true);
} else {
response = Utility.constructJSON("editOrder", false,
"Cannot insert to database!");
}
return response;
}
Everything works fine when I use GET, but when I use POST, all params became null in "editOrder" function.
Please help, thank you.
OK, I solved my problem. Simply, use RequestParams instead of JSONObject:
public void wsEditMaster(final RequestParams params) {
client.post("http://" + serverIP + "/DHD/general/editorder", params, new AsyncHttpResponseHandler() {

Android JSON POST with OKHTTP

I´m looking for a solution to implement a JSON-POST request with OKHTTP. I´ve got an HTTP-Client.java file which handles all the methods (POST, GET, PUT, DELETE) and in the RegisterActivity I´d like to POST the user-data (from the input fields) JSON-formatted to the server.
This is my HTTP-Client.java
public class HttpClient{
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
public static OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
#Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url.host(), cookies);
}
#Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<Cookie>();
}
})
.build();
public static Call post(String url, String json, Callback callback) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body.create(JSON, json))
.build();
Call call = client.newCall(request);
call.enqueue(callback);
return call;
}
}
... and this is the onClick-Part from the RegisterActivity
btnRegRegister.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//TODO
String registerData = "{\"email\":\"" + etRegisterEmail.getText().toString() + "\",\"password\":\"" + etRegisterPasswort.getText().toString() + "\"}";
try {
HttpClient.post(ABSOLUTE_URL, registerData, new Callback(){
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String resp = response.body().string();
if (resp != null) {
Log.d("Statuscode", String.valueOf(response.code()));
Log.d("Body", response.body().string());
}
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
Everytime I start the app it crashes when I click the Register-Button caused by a FATAL EXPECTION 'android.os.NetworkOnMainThreadException'
I´ve alread read something about the AsyncTask but I don´t know exactly how to do this.
Try my code below
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
Map<String, String> params = new HashMap<String, String>();
params.put("msisdn", "123123");
params.put("name", "your name");
JSONObject parameter = new JSONObject(param);
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(JSON, parameter.toString());
Request request = new Request.Builder()
.url(url)
.post(body)
.addHeader("content-type", "application/json; charset=utf-8")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.e("response", call.request().body().toString());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("response", response.body().string());
}
});
It's because you are trying to execute the HTTP query on the main thread (or UI thread). You shouldn't do a long task on the main thread because your app will hang, because the drawing routines are executed in that thread (hence his another name "UI Thread"). You should use another thread to make your request. For example:
new Thread(){
//Call your post method here.
}.start();
The Android asynctask is a simple class to do asynchronous work. It executes first his "onPreExecute" method on the calling thread, then his "doInBackground" method on a background thread, then his "onPostExecute" method back in the calling thread.
Try using Retrofit library for making Post request to the server. This provides a fast and reliable connection to the server.
You can also use Volley library for the same.

How to Set Tag to the request and get it from Response Volley asynchronous request?

I have an Android application with multiple REST Api's. The API's are managed using the Volley library. The response is getting and it's woking fine. But when I make asynchronous requests, I can't identify the response of each request.
My request method is this:
private void httpCall(String URL, String json, String session key, int type) {
try {
SSLContext sslcontext = SSLContext.getInstance("TLSv1");
sslcontext.init(null,
null,
null);
SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());
HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory);
Log.i(REQUEST_TAG, "httpCall=url" + url + "::type" + type);
Log.i(REQUEST_TAG, "httpCall=json" + json);
} catch (Exception e) {
e.printStackTrace();
}
if (mContext != null)
mQueue = CustomVolleyRequestQueue.getInstance(mContext).getRequestQueue();
else
mQueue = CustomVolleyRequestQueue.getInstance(mActivity).getRequestQueue();
JSONObject mJSONObject;
final CustomJSONObjectRequest jsonRequest;
try {
if ((json != null) && (json.trim().length() > 0)) {
mJSONObject = new JSONObject(json);
} else {
mJSONObject = new JSONObject();
}
jsonRequest = new CustomJSONObjectRequest(sessionkey, type, url, mJSONObject, this, this);
// Wait 20 seconds and don't retry more than once
jsonRequest.setRetryPolicy(new DefaultRetryPolicy(
(int) TimeUnit.SECONDS.toMillis(20),
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
jsonRequest.setTag(REQUEST_TAG);
mQueue.add(jsonRequest);
} catch (JSONException e) {
e.printStackTrace();
}
}
Is there any option to set a tag to the request and get the same from the response?. So that I can identify the current request and response. I don't know this is a duplicate question, but I didn't get a proper explanation for this.
My Response method is:
#Override
public void onResponse(Object response) {
if (response != null) {
// I want to trigger the request tag from here
mCallBack.onSuccessData(response);
}
}
The request and response method are in same class and the class implemented Response.Listener, Response.ErrorListener.
The tag you assign to a Request is stored to the variable mTag which is persisted throughout the life cycle of the Request.
public Request<?> setTag(Object tag) {
mTag = tag;
return this;
}
For my applications I have slightly modified the following Volley classes:
In class Request change visibility of mTag from private to protected
/** An opaque token tagging this request; used for bulk cancellation. */
protected Object mTag;
In class Response, add Object tag to the callback function onResponse defined in interface Listener
/** Callback interface for delivering parsed responses. */
public interface Listener<T> {
/** Called when a response is received. */
public void onResponse(Object tag, T response);
}
In classes which implement interface Response.Listener, like JsonRequest
#Override
protected void deliverResponse(T response) {
mListener.onResponse(mTag, response);
}

Using Volley Library in android in a structured pattern

I am using Volley to make network calls in my application... For many screens ...(say fragments) I am making various requests like LoginRequest, FetchUsers Request, FetchExams Request..... and handling response and errors in each fragments.
What is the best approach I can use like....
1. Subclass a request
2. Create an interface/callbacks
3. Get results/response or error response in my fragment...
This is how I am doing ....creating many such methods.....
private void syncAllUsers() {
progressDialog.setMessage("Loading Users...");
StringRequest jsonProductCategoryFetchRequest = new StringRequest(Request.Method.POST, Config.SELECT_USERS,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
if(Constants.DEBUG_MODE_ON)
Log.d(Constants.DEBUG_LOG, "RESPONSE for Teachers: "+response);
JSONObject result = new JSONObject(response);
boolean code = result.getBoolean("error");
if (!code) {
//Get the Users Json Array
JSONArray ja = result.getJSONArray("users");
if(ja != null) {
db.deleteAllUsers();
for (int i = 0; i < ja.length(); i++) {
JSONObject jobj = ja.getJSONObject(i);
User user = new User();
user.setId(jobj.getInt(User.KEY_ID));
user.setName(jobj.getString(User.KEY_NAME));
user.setEmail(jobj.getString(User.KEY_EMAIL));
user.setPhone(jobj.getString(User.KEY_PHONE));
user.setGender(jobj.getString(User.KEY_GENDER));
user.setUsername(jobj.getString(User.KEY_USERNAME));
user.setPassword(jobj.getString(User.KEY_PASSWORD));
user.setOrganization_id(jobj.getString(User.KEY_ORGANIZATION_ID));
user.setDob(jobj.getString(User.KEY_DOB));
user.setStatus(jobj.getString(User.KEY_STATUS));
user.setApi_key(jobj.getString(User.KEY_API_KEY));
user.setDate_created(jobj.getString(User.KEY_DATE_CREATED));
user.setRole_id(jobj.getInt(User.KEY_ROLE_ID));
//Delete local Teachers before updating
db.createUser(user);
} // for loop ends
}
}
//syncAllExams();
progressDialog.dismiss();
getActivity().finish();
startActivity(new Intent(getActivity(), MainActivity.class));
} catch (Exception e) {
Log.d(Constants.DEBUG_LOG, "Exception Syncing Users: " , e);
Toast.makeText(getActivity(),"Something went wrong while fetching users", Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
getActivity().finish();
startActivity(new Intent(getActivity(), MainActivity.class));
}
}
} , new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if(Constants.DEBUG_MODE_ON)
Log.d(Constants.DEBUG_LOG, "Error Response for Users : "+error.getCause()+""+error.toString());
Toast.makeText(getActivity(), getString(R.string.no_internet), Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
getActivity().finish();
startActivity(new Intent(getActivity(), MainActivity.class));
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put(User.KEY_ORGANIZATION_ID, preferencesManager.getOrganizationID());
params.put(User.KEY_API_KEY, preferencesManager.getApiKey());
Log.d("Registration", "PARAMS : " + params.entrySet());
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> params = new HashMap<String, String>();
// params.put("Content-Type", "application/json; charset=utf-8");
params.put("Content-Type", "application/x-www-form-urlencoded");
String auth = preferencesManager.getApiKey();
params.put("Authorization", auth);
return params;
}
};
MyApplication.getInstance().addToReqQueue(jsonProductCategoryFetchRequest);
}
I think there would be a clean way to perform this. Any suggestions.
I have been using this class for creating requests, it transforms your json into your object automaticaly with gson. Find example here:
https://gist.github.com/ficusk/5474673
Create Request Manager.. Which is only dealing with Requesting your web services. That Manager should also handle any network error and other errors which are not application layer.
Use this request manager from your Model classes where your business logic is. Send Request Parameter as JSON.. Also you can send your different listeners from to Request Manager So that when web service response comes it directly comes to you Model class and you can parse JSON response according to your needs.
This way parsing logic stays with Model class and Requesting logic stays with Request manager.. So in future if you change web service address you need to check only one place.. And if you change request and response parameter for webservice you dont need to change request manager and only Model class...
There might be some other ways..
public final class RequestManager {
private static final String ROOT_HOST = //Your Webservice Host Root.
private RequestQueue queue;
public RequestManager(final Context context) {
queue = Volley.newRequestQueue(context);
}
//Internal Calling method .. Not exposed..
private void doRequest(final int method, final String url, final JSONObject jsonParam, final Response.Listener<JSONObject> listener,
final Response.ErrorListener errlsn) {
JSONObjectRequest jsonObjectRequest = new SONObjectRequest(method, url, jsonParam, listener, errlsn);
queue.add(jsonObjectRequest);
}
public void doLogin(final User user, final Response.Listener<JSONObject> listener, final Response.ErrorListener errlsn)
throws Exception {
// Make login request JSON here
if (user == null || listener == null || errlsn == null) {
//throw Exception
}
final JSONObject jsonObj = new JSONObject();
//Convert user object to JSON Object
doRequest(Request.Method.GET, LOGIN_URL, jsonObj, listener, errlsn);
}
}

Android volley login session

I am using RESTful service. After I login I cannot access other services with the app. It says I am not logged in. I believe I am doing something wrong with the HttpClientStack.. Here is the code..
public class HttpClientStackObject {
public static DefaultHttpClient httpClient;
public static HttpClientStack httpClientStack;
public static HttpClientStack getHttpClientStack() {
if(httpClientStack == null){
httpClient = new DefaultHttpClient();
httpClientStack = new HttpClientStack(httpClient);
}
return httpClientStack;
}
}
Login.java
RequestQueue queue = Volley.newRequestQueue(this, HttpClientStackObject.getHttpClientStack());
jsonObjectRequest = new JsonObjectRequest(
Request.Method.POST, URL, jsonOb,
new ResponseListener(), new ErrorListener());
queue.add(jsonObjectRequest);

Categories

Resources