Handling Sessions on Google App Engine with Androi

2019-03-12 14:29发布

I'm starting to write an app whereby a mobile app (Android/IPhone) will communicate with the GAE backend (Python) through a series of Web API calls using JSON.

I can't use Google Accounts for authentication so I need to implement my own auth. I have an idea of how to do this, but I'm not sure if there is a better way.

Can anyone help with some code examples/suggestions of how to achieve the below please?

Method

  1. Mobile app calls a Login method on the server which authenticates and creates a session key in the store and returns this to the app - not sure how to generate the key/session or where on the request/response it should be.
  2. On every call, the app passes this key for the server to authenticate and allows the action if it passes.
  3. User should not have to login on mobile again unless they explicitly logout or lose the key.

Login Method - without key generation

class Login(webapp.RequestHandler):
def post(self):
    args = json.loads(self.request.body)
    email = args['e']
    pwd = args['p']
    ret = {}
    user = User.gql('WHERE email = :1', email).get()
    if user and helpers.check_password(pwd, user.password):
        ret['ret_code'] = 0
        ret['dn'] = user.display_name
    else:
        ret['ret_code'] = 1

    self.response.headers['Content-Type'] = 'application/json'
    self.response.out.write(json.dumps(ret))

6条回答
叼着烟拽天下
2楼-- · 2019-03-12 14:49

Have a look at webapp2 and webapp2 extras with sessions, auth and JSON

查看更多
手持菜刀,她持情操
3楼-- · 2019-03-12 14:51

There are many ways to do this.

1) When you check the users login details if it checks out you can then create a random UUID or string and store the User object in memcache with the random string as the Key and the User Object as the value. Then return the random string along with your response headers. On the mobile when you are parsing the response, get this header and store it in the local cache. On all further requests keep sending this key back in the request header and in your controller get the User object from memcache using this key and proceed. If the object is not in memcache you can send back a response which prompts the user to log in.

2) If you dont want to use memcache you can store the User object in the session and on the client side while parsing the response get the session id from the response. Its usually JSESSIONID. Then store that and resend it with further requests. In the controller you can check if the current session has the user object else force login.

1) Another way to go would be to return the appengine key for the user along with the response and resend it.

Just google get response header from response. Then get the SESSIONID/JSESSIONID header, store and add the field with the same name and value to all further request headers. Thats the easiest way.

My first answer on stackoverflow and no code exapmles, dangit if only i knew python.

查看更多
姐就是有狂的资本
4楼-- · 2019-03-12 14:52

I think you should use features webapp2 providing to implement your custom registration.

from webapp2_extras import auth
from google.appengine.api import users

class RegisterHandler(webapp2.RequestHandler):
    def post(self):
        email=self.request.POST['email']
        password=self.request.POST['password']

        #Let webapp2 handle register and manage session
        user = auth.get_auth().store.user_model.create_user('own:'+str(email), password_raw=password,email=email)
        #user (True, User(key=Key('User', 80001), auth_ids=[u'own:useremail@mail.com'],email='useremail@mail.com',password=u'hashed_password',...))

        if not user[0]: #user is a tuple
            self.response.write(user[1]) # Error message
        else:
            #You can extend your User Model e.g UserProfile(User): or have a UserProperty in your profile model as the example.  
            profile=UserProfile(user=users.User(user[1].email)).put()

            self.response.write(str(profile.key()))
class LoginHandler(webapp2.RequestHandler): 

    def post(self):

        email = self.request.POST.get('email')
        email = self.request.POST.get('password')
        # Try to login user with password
        # Raises InvalidAuthIdError if user is not found
        # Raises InvalidPasswordError if provided password doesn't match with specified user
        try:
            auth.get_auth().get_user_by_password('own:'+email, password)
            #Return user_session with User id, 
        except InvalidPasswordError, InvalidAuthIdError:
            #Error

You can check user logged in by:

if auth.get_user_by_session():
    #Logged in      
else:
    #Not logged in

On your client application(Android, IOS). You only have to store the response cookie and send it for every sub sequence requests.

Good luck :)

查看更多
姐就是有狂的资本
5楼-- · 2019-03-12 14:57

I cannot see why you would need a session? Sessions on App Engine are persisted in the data store, so if you can keep your requests stateless, I encourage you to do so.

As you will have your own user service which will authenticate the users, I suggest you use Digest authentication, as the secret is never included in the request.

There are libraries implementing Digest for most client and server platforms.

查看更多
看我几分像从前
6楼-- · 2019-03-12 14:58

If you dont explicitly want to use Sessions etc. you can simply use the Datastore. Try following this:

  1. Get a unique deviceID/email to identify each unique user.
  2. On request from a specific user, generate a random authentication key, and store it attached to the user's email/deviceID and probably the current timestamp and a loggedIn flag.

SO you have:

User email/id: someone@example.com
password: xxxxxxxxxx
Key : 2131231312313123123213
Timestamp: 20:00 12-02-2013
loggedIn : boolean value

This can be database model. Now whenever the user logs in:

  • Check email, password combination.
  • If valid, generate random key, and update the datastore with the new key
  • update timestamp with current time, and set loggedIn to True
  • Now return the key back to the client (Android/iPhone) in a JSON object.

Now on every request, Check the received key against the one in your datastore, and if loggedIn flag is set to true. If both OK, process the request.

Also, on Logout:

  • Just set the loggedIn flag in the datastore to False.

Hope this helps :)

查看更多
Animai°情兽
7楼-- · 2019-03-12 14:58

Try gae-sessions for session management. It creates secure cookies for you and allows you to easily associate data with each user. Just provide your own logic for the initial authentication.

It was built specifically for App Engine and is pretty popular and super fast/scalable.

https://github.com/dound/gae-sessions

查看更多
登录 后发表回答