GAE enforcing sign in by app.yaml, python decorato

2019-02-05 14:35发布

问题:

I'm using 'login' option in my app.yaml configuration file for a GAE application. Looks like this:

- url: /admin/.*
  script: myapp.app
  login: admin

- url: /.*
  script: myapp.app
  login: required

UPDATE (by suggestion of bossylobster): I want a user always signed in (unsigned users can't do anything), and I need to know who the user is. Actually, I need OAuth2 credentials to communicate with Google APIs (for example, I need to fetch some user's info with Google Profiles API, and write in the user's calendar with Google Calendar API). Finally, I need an admin user to perform some operations (like create new domain's users, with Google Provisioning API)

I'm using google-api-client library, and playing around with oauth2 decorators. Then, in my RequestHandlers, I have this:

class MainHandler(webapp.RequestHandler):

  @decorator.oauth_aware
  def get(self):
    if decorator.has_credentials():
      # do something

    else:
      url = decorator.authorize_url()
      self.response.out.write(template.render('templates/index.html',
           {'authorize_url': url}))

Finally, I've read about another method:

user = users.get_current_user()
if user:
  # do something
else:
  greeting = ("<a href=\"%s\">Sign in or register</a>." %
    users.create_login_url("/"))

  self.response.out.write("<html><body>%s</body></html>" % greeting)

What is the best method to handle the user's authentication to fit my needs (see UPDATE)?

Many thanks in advance

回答1:

I think you may be confusing what the OAuth 2.0 decorator does vs. the other two approaches.

The OAuth 2.0 decorator is not specific to your app, you would use it if you want to get OAuth 2.0 credentials for your users and then use those to communicate with Google APIs.

The other two are simply ways to get the user information from a session cookie that is set by App Engine.

If you really want a decorator, you would use login_required, documented here:
https://developers.google.com/appengine/docs/python/tools/webapp/utilmodule

There is no one best approach between specifying in app.yaml, checking if users.get_current_user is None or using @login_required on specified handlers.

A rough approximation of the three distinct times you'd want to use these are the following:

1) If you want users to be logged in, but don't need to know the specific user, use login: required in app.yaml.

2) If want to know the user, but also have a fallback if the user is not logged in, use users.get_current_user and tailor your behavior to the user or to None if that is the returned value.

3) If you want to know the user and always have one logged in, use @login_required.

UPDATE:

(Based on a further explanation of needs.) Since you always want to log your users in and always want OAuth 2.0 credentials for them, you should always use decorator.oauth_required.

As for using the APIs, only the Google Calendar API can be used with the google-api-python-client library. The Google Apps Provisioning API is a Google Data API, while the Calendar API is a discovery-based API.

As a result, you'll need to use the gdata-python-client library to use the Provisioning API. You'll need to manually convert from a oauth2client.client.OAuth2Credentials object to a gdata.gauth.OAuth2Token object to use the same token for either one.

When using OAuth2Decorator, you'll be able to access an instance of oauth2client.client.OAuth2Credentials via decorator.credentials().

SECOND UPDATE:

I recently added support for this to gdata-python-client.

from gdata.gauth import OAuth2TokenFromCredentials
auth_token = OAuth2TokenFromCredentials(decorator.credentials())
auth_token.authorize(client)

The implementation allows the two token/credentials objects decorator.credentials() and auth_token to stay in sync, no matter which object you change values on.