ndb how google engine delete create app python google-app-engine google-api google-cloud-datastore

python - how - ndb properties



Administrar la autenticación de los usuarios en Google App Engine (1)

Entiendo la confusión, pero el sistema está "funcionando como se diseñó".

En cualquier momento, un manejador de GAE puede tener cero o un "usuario conectado" (el objeto devuelto por users.get_current_user() , o None si no hay un usuario conectado) y cero o más "tokens de autorización de oauth2" (para cualesquiera usuarios y alcances han sido otorgados y no revocados).

No hay ninguna restricción que obligue a las cosillas oauth2 a coincidir, en cualquier sentido, con el "usuario conectado, si hay alguno".

Recomiendo consultar la muestra muy simple en https://code.google.com/p/google-api-python-client/source/browse/samples/appengine/main.py (para ejecutarlo, tendrás para clonar todo el paquete "google-api-python-client", luego copie en los directorios del directorio google-api-python-client/source/browse/samples/appengine apiclient/ y oauth2client/ de este mismo paquete y httplib2 desde https://github.com/jcgregorio/httplib2 - y también personalice client_secrets.json - sin embargo, no necesita ejecutarlo, solo para leer y seguir el código).

Este ejemplo ni siquiera usa users.get_current_user() : no lo necesita ni le importa: solo muestra cómo usar oauth2 , y no hay conexión entre la celebración de un token oauth2 oauth2 y el servicio del users . . (Esto le permite, por ejemplo, que cron ejecute en nombre de uno o más usuarios determinadas tareas más adelante; cron no inicia sesión, pero no importa). Si los tokens oauth2 se almacenan y recuperan correctamente, puede usarlos. ellos).

Entonces, el código crea un decorador a partir de los secretos del cliente, con scope=''https://www.googleapis.com/auth/plus.me'' , luego usa @decorator.oauth_required en el manejador para asegurar la autorización, y con el decorador http autorizado, obtiene

user = service.people().get(userId=''me'').execute(http=http)

con service creado anteriormente como discovery.build("plus", "v1", http=http) (con un http diferente no autorizado).

Si ejecuta esto localmente, es fácil agregar un inicio de sesión falso (recuerde, el inicio de sesión de usuario es falso con dev_appserver) para que users.get_current_user() devuelva [email protected] o cualquier otro correo electrónico falso que ingrese en la pantalla de inicio de sesión falso - y esto de ninguna manera impide que el flujo de oauth2 completamente separado siga funcionando según lo previsto (es decir, exactamente de la misma manera que sin un inicio de sesión falso).

Si despliega la aplicación modificada (con un inicio de sesión de usuario adicional) en producción, el inicio de sesión tendrá que ser real, pero es tan indiferente y separado de la parte oauth2 de la aplicación.

Si la lógica de su aplicación requiere restringir el token oauth2 al usuario específico que también ha iniciado sesión en su aplicación, tendrá que implementarlo usted mismo, por ejemplo, estableciendo el scope en ''https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.profile.emails.read'' (más cualquier otra cosa que necesite), obtendrá de service.people().get(userId=''me'') a objeto del user con (entre otras cosas) un atributo de emails en el que puede verificar que el token de autorización es para el usuario con el correo electrónico que desea autorizar (y tomar medidas correctivas de otro modo, p. ej. mediante una URL de cierre de sesión & c). ((Esto se puede hacer de forma más sencilla y, en cualquier caso, dudo que realmente necesite dicha funcionalidad, pero solo quería mencionarla)).

Estoy trabajando en una aplicación web basada en el motor de la aplicación de Google. La aplicación utiliza las API de API de Apis. Básicamente, cada controlador se extiende desde este BaseHandler y, como primera operación de cualquier get / post, se ejecuta checkAuth.

class BaseHandler(webapp2.RequestHandler): googleUser = None userId = None def checkAuth(self): user = users.get_current_user() self.googleUser = user; if user: self.userId = user.user_id() userKey=ndb.Key(PROJECTNAME, ''rootParent'', ''Utente'', self.userId) dbuser = MyUser.query(MyUser.key==userKey).get(keys_only=True) if dbuser: pass else: self.redirect(''/'') else: self.redirect(''/'')

La idea es redirigir a / si ningún usuario está conectado a través de Google O si no hay un usuario en mi base de datos de usuarios que tengan esa ID de Google.

El problema es que puedo iniciar sesión con éxito en mi aplicación web y realizar operaciones. Luego, desde Gmail, o Salga de cualquier cuenta de Google PERO si trato de seguir usando la aplicación web, funciona. Esto significa que users.get_current_user () aún devuelve un usuario válido (válido pero realmente VIEJO). ¿Es eso posible?

ACTUALIZACIÓN IMPORTANTE : Entiendo lo explicado en el comentario de Alex Martelli: existe una cookie que mantiene válida la anterior autenticación GAE. El problema es que la misma aplicación web también aprovecha la biblioteca de Google Api Client para Python https://developers.google.com/api-client-library/python/ para realizar operaciones en Drive y Calendar. En las aplicaciones de GAE, dicha biblioteca se puede utilizar fácilmente a través de decoradores que implementan todo el flujo de OAuth2 ( https://developers.google.com/api-client-library/python/guide/google_app_engine ).

Por lo tanto, mis manejadores obtienen / publican métodos decorados con oauth_required como este

class SomeHandler(BaseHandler): @DECORATOR.oauth_required def get(self): super(SomeHandler,self).checkAuth() uid = self.googleUser.user_id() http = DECORATOR.http() service = build(''calendar'', ''v3'') calendar_list = service.calendarList().list(pageToken=page_token).execute(http=http)

Donde el decorador es

from oauth2client.appengine import OAuth2Decorator DECORATOR = OAuth2Decorator( client_id=''XXXXXX.apps.googleusercontent.com'', client_secret=''YYYYYYY'', scope=''https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive.file'' )

Por lo general, funciona bien. Sin embargo (!!) cuando la aplicación está inactiva durante mucho tiempo sucede que el decorador de oauth2 me redirige a la página de autenticación de Google donde, si cambio de cuenta (tengo 2 cuentas diferentes) ocurre algo raro: la aplicación todavía está registrada como la cuenta anterior (recuperada a través de users.get_current_user ()) mientras que la biblioteca del cliente api, y por lo tanto el decorador oauth2, devuelve datos (unidad, calendario, etc.) pertenecientes a la segunda cuenta.

Lo cual no es REALMENTE apropiado.

Siguiendo el ejemplo anterior (clase SomeHandler) supongamos que estoy registrado como Cuenta A. Los usuarios.get_current_user () siempre devuelven A como se esperaba. Ahora supongamos que dejé de usar la aplicación, después de un tiempo largo el oauth_required me redirige a la página de la cuenta de Google. Por lo tanto, decido (o me equivoco) que el registro es como Cuenta B. Al acceder al método Obtener de la clase SomeHandler el ID de usuario (recuperado a través de users.get_current_user () es A mientras que la lista de calendarios regresa a través del objeto de servicio (Google Api) biblioteca del cliente) es la lista de calendarios que pertenecen a B (el usuario real actualmente registrado).

¿Estoy haciendo algo mal? es algo esperado?

Otra actualización

esto es después de la respuesta de Martelli. He actualizado los controladores de esta manera:

class SomeHandler(BaseHandler): @DECORATOR.oauth_aware def get(self): if DECORATOR.has_credentials(): super(SomeHandler,self).checkAuth() uid = self.googleUser.user_id() try: http = DECORATOR.http() service = build(''calendar'', ''v3'') calendar_list = service.calendarList().list(pageToken=page_token).execute(http=http) except (AccessTokenRefreshError, appengine.InvalidXsrfTokenError): self.redirect(users.create_logout_url( DECORATOR.authorize_url())) else: self.redirect(users.create_logout_url( DECORATOR.authorize_url()))

así que, básicamente, ahora uso oauth_aware y, en caso de que no tenga ninguna credencial, cierro la sesión del usuario y lo redirijo al DECORATOR.authorize_url ()

Me di cuenta de que después de un período de inactividad, el controlador genera excepciones AccessTokenRefreshError y appengine.InvalidXsrfTokenError (pero el método has_credentials () devuelve True). Los atrapo y (nuevamente) redirijo el flujo al cierre de sesión y autorizo_url ()

Parece funcionar y parece ser robusto para el cambio de cuentas. ¿Es una solución razonable o no estoy considerando algunos aspectos del problema?