7

I'm new to flutter. Basically I'm using code Igniter framework for my web application. I created REST API for my web app, after user login using API all the methods check for the session_id if it exists then it proceeds, and if it doesn't then it gives

{ ['status'] = false, ['message'] = 'unauthorized access' }

I'm creating app with flutter, when i use the http method of flutter it changes session on each request. I mean, it doesn't maintain the session. I think it destroys and creates new connection each time. Here is thr class method which i use for api calls get and post request.

class ApiCall {  
  static Map data;
  static List keys;

static Future<Map> getData(url) async {
 http.Response response = await http.get(url);
 Map  body =  JSON.decode(response.body);
 data = body;
 return body;
}

static Future postData(url, data) async {
Map result;    
http.Response response = await http.post(url, body: data).then((response) {
  result = JSON.decode(response.body);
}).catchError((error) => print(error.toString()));

data = result;
keys = result.keys.toList();

return result;  
}

I want to make API request and then store session_id, And is it possible to maintain session on the server so i can manage authentication on the web app it self.?

user8854564
  • 71
  • 1
  • 2
  • 1
    Hi , as Richard said Http is stateless , and you can attach headers as a parameter for http.post function. Also With mobile apps , APIs usually work with Authorization Tokens , Auth headers and such usually : https://flutter.io/cookbook/networking/authenticated-requests/ Explained here: https://scotch.io/tutorials/the-ins-and-outs-of-token-based-authentication and i think this does sth simillar for code igniter(i've never worked with code igniter) https://github.com/benedmunds/CodeIgniter-Ion-Auth – behzad.robot May 13 '18 at 18:58

1 Answers1

20

HTTP is a stateless protocol, so servers need some way to identify clients on the second, third and subsequent requests they make to the server. In your case you might authenticate using the first request, so you want the server to remember you on subsequent requests, so that it knows you are already authenticated. A common way to do this is with cookies.

Igniter sends a cookie with the session id. You need to gather this from each response and send it back in the next request. (Servers sometimes change the session id (to reduce things like clickjacking that we don't need to consider yet), so you need to keep extracting the cookie from every response.)

The cookie arrives as an HTTP response header called set-cookie (there may be more than one, though hopefully not for simplicity). To send the cookie back you add a HTTP request header to your subsequent requests called cookie, copying across some of the information you extracted from the set-cookie header.

Hopefully, Igniter only sends one set-cookie header, but for debugging purposes you may find it useful to print them all by using response.headers.forEach((a, b) => print('$a: $b'));. You should find Set-Cookie: somename=abcdef; optional stuff. We need to extract the string up to, but excluding the ;, i.e. somename=abcdef

On the next, and subsequent requests, add a request header to your next request of {'Cookie': 'somename=abcdef'}, by changing your post command to:

http.post(url, body: data, headers:{'Cookie': cookie})

Incidentally, I think you have a mismatch of awaits and thens in your code above. Generally, you don't want statics in classes, if they should be top level functions instead. Instead you could create a cookie aware class like:

class Session {
  Map<String, String> headers = {};

  Future<Map> get(String url) async {
    http.Response response = await http.get(url, headers: headers);
    updateCookie(response);
    return json.decode(response.body);
  }

  Future<Map> post(String url, dynamic data) async {
    http.Response response = await http.post(url, body: data, headers: headers);
    updateCookie(response);
    return json.decode(response.body);
  }

  void updateCookie(http.Response response) {
    String rawCookie = response.headers['set-cookie'];
    if (rawCookie != null) {
      int index = rawCookie.indexOf(';');
      headers['cookie'] =
          (index == -1) ? rawCookie : rawCookie.substring(0, index);
    }
  }
}
Richard Heap
  • 48,344
  • 9
  • 130
  • 112
  • 1
    Can you please elaborate, I'm new to flutter and cookies thing. So, this means after each request a new connection is made to the site which won't keep the session alive? – user8854564 May 11 '18 at 20:42
  • 3
    This isn't actually specific to Dart or Flutter. It's an HTTP thing. HTTP is a stateless protocol, which makes a new connection to the server whenever it wants. So you don't have a permanent connection to the server. Cookies are the answer to this - think of them as a ticket. Every time the server sends you a response it sends you a ticket. If you send that ticket back it knows it's you, as you were the only person it gave that ticket to. When the server receives a request without a cookie it assumes it's a new subscriber and creates a new session, which is why to keep seeing new sessions. – Richard Heap May 11 '18 at 20:51
  • Edited the answer with more detail – Richard Heap May 13 '18 at 00:18
  • 1
    If this answer was useful, it's customary to upvote it and/or accept it. If it wasn't useful, please let me know. – Richard Heap May 14 '18 at 00:44
  • @RichardHeap can you explain why on updateCookie() you would take only the 1st cookie from the response and not everything from the Set-Cookie header? – Germán Mar 04 '19 at 21:29
  • 1
    @Germán please see Iarly's answer for multiple cookies [here](https://stackoverflow.com/questions/52241089/how-do-i-make-an-http-request-using-cookies-on-flutter) – Richard Heap Mar 04 '19 at 21:34