Gauth
Djangae includes two applications to aid authentication and user management with
App Engine. Each provides both an abstract class, to extend if you're defining your own custom User model, or a concrete version to use in place of 'django.contrib.auth.models.User'
. Also provided are custom authentication backends which delegate to the App Engine users API and a middleware to handle the link between the Django's user object and App Engine's (amongst other things).
Using the Datastore
Allows the use of Django's permissions system on the Datastore, despite it usually requiring many-to-many relationships, which are not supported on the Datastore.
Setup
- Add
'djangae.contrib.gauth_datastore'
toINSTALLED_APPS
probably after'django.contrib.auth'
. - Replace
'django.contrib.auth.middleware.AuthenticationMiddleware'
with'djangae.contrib.gauth.middleware.AuthenticationMiddleware'
. - Set
AUTH_USER_MODEL = 'gauth_datastore.GaeDatastoreUser'
in your settings file to use the supplied user model, or create your own by subclassingdjangae.contrib.gauth_datastore.models.GaeAbstractDatastoreUser
. - Add the backend to
AUTHENTICATION_BACKENDS
in your settings file eg:
AUTHENTICATION_BACKENDS = (
'djangae.contrib.gauth_datastore.backends.AppEngineUserAPIBackend',
...
)
Permissions
The Datastore-based user models have a user_permissions
list field, which takes the place of the usual many-to-many relationship to a Permission
model. For groups, Djangae provides djangae.contrib.gauth_datastore.Group
, which again has a list field for storing the permissions. This Group
model is registered with the Django admin automatically for you.
Using a relational database (CloudSQL)
Setup
- Add
'djangae.contrib.gauth_sql'
toINSTALLED_APPS
probably after'django.contrib.auth'
. - Replace
'django.contrib.auth.middleware.AuthenticationMiddleware'
with'djangae.contrib.gauth.middleware.AuthenticationMiddleware'
. - Set
AUTH_USER_MODEL = 'gauth_sql.GaeUser'
in your settings file to use the supplied user model or create your own by subclassingdjangae.contrib.gauth_sql.models.GaeAbstractUser
. - Add the backend to
AUTHENTICATION_BACKENDS
in your settings file eg:
AUTHENTICATION_BACKENDS = (
'djangae.contrib.gauth_sql.backends.AppEngineUserAPIBackend',
...
)
Using your own permissions system
If you want to write your own permissions system, but you still want to take advantage of the authentication provided by the Google Users API, then you may want to subclass djangae.contrib.gauth.models.GaeAbstractBaseUser
.
Authentication for unknown users
By default Djangae will grant access for unknown users who are signed in with a Google account.
Add DJANGAE_CREATE_UNKNOWN_USER=True
(the default) to your settings and Djangae will always grant access (for authenticated Google Accounts users), creating a Django user if one does not exist. If DJANGAE_CREATE_UNKNOWN_USER=False
then Djangae will deny access for unknown users (unless the user is an administrator for the App Engine application).
If there is a Django user with a matching email address and username set to None
then Djangae will update the Django user, setting the username to the Google user ID. If there is a user with a matching email address and username set to another user ID then Djangae will set the existing user's email address to None
and create a new Django user.
App Engine administrators are always granted access, and a Django user will be created if one does not exist.
Customizing user data syncing
By default djangae.contrib.gauth.middleware.AuthenticationMiddleware
syncs email and superuser status. In case you need to customize this behaviour (for example sync first and last names as well) you could inherit from AuthenticationMiddleware
and override sync_user_data
method.
For example if we would like to sync only an email address, not a superuser status, we could do the following:
class MyAuthenticationMiddleware(AuthenticationMiddleware):
def sync_user_data(self, django_user, google_user):
if django_user.email != google_user.email():
django_user.email = google_user.email()
django_user.save()
and replace 'djangae.contrib.gauth.middleware.AuthenticationMiddleware'
with your middleware.
Pre-creating Users
You can add users to the database before they have logged in. If you've set DJANGAE_CREATE_UNKNOWN_USER
to False
then only users who already exist in the database can log in.
Users are keyed by their Google User ID, which is stored in the username
field. However, it is impossible to know what a user's Google User ID will be until they have logged in. Therefore, pre-created users who have not yet logged in are keyed by their email address (case insensitively). To create a user who has not yet logged in you can either:
- Create the user via the Django admin, leaving the
username
field (labelled "User ID") blank. Or... - Create the user via the remote shell with
get_user_model().objects.pre_create_google_user("user@example.com")
.
get_or_create
with pre-created Users
When using pre-created Users you should be careful using get_or_create
. The line:
User.objects.get_or_create(email=email)
will result in error, if the pre-created user already exists with the email that is case-sensitive-different, but case-insensitive-equal to the provided value.
For instance, if you have pre-created user with email: JOHN@gmail.com
and you have get_or_create
with email John@gmail.com
, you will end up trying to create a new user and failing because both versions (JOHN@gmail.com
and John@gmail.com
) have the same case-insensitive value.
To avoid the problem, when using get_or_create
, you should use email_lower
instead like this:
User.objects.get_or_create(email_lower=email.lower(), defaults={"email": email})
Username/password authentication
As well as using Djangae's Google Accounts-based authentication, you can also use the standard authentication backend from django.contrib.auth. They can work alongside each other. Simply include both, like this:
AUTHENTICATION_BACKENDS = (
'djangae.contrib.gauth_datastore.backends.AppEngineUserAPIBackend',
'django.contrib.auth.backends.ModelBackend',
)
MIDDLEWARE_CLASSES = (
'djangae.contrib.gauth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
Switching accounts
There is a switch_accounts
view which allows a user to change which of their Google accounts they're logged in with.
The URL for the user to be sent to afterwards should be provided in `request.GET['next']``.
Learn more about Google multiple sign-in on App Engine here.
Example usage:
Include GAuth urls in your main urls.py file.
url(r'^gauth/', include(djangae.contrib.gauth.urls))
Use this URL to add "Switch account" functionality for user:
{% raw %} Switch account {% endraw %}