■
App Engine Helper for DjangoはModelFormが使えないといった問題があり,それらを改善したプロジェクトとしてapp-engine-patchが紹介されている.しかしapp-engine-patchも既に開発が止まっていてDjango-nonrelを使えとのこと.Django-nonrelを使えばApp Engine上でもDjangoの機能の多くを利用することができる.一方でGAE DjangoやAEPにあったGoogleアカウント認証機能やログインURLテンプレートタグはDjango-nonrelでは失われているようだ.というわけ認証サポートをサクっと作ってみた.
まずはdjangoのモデルとGAE上のユーザを結びつけるモデルの定義.
project_dir/gaeutils/auth/models.py
from django.db import models from django.contrib.auth.models import User class GoogleProfile(models.Model): user = models.ForeignKey(User) google_user_id = models.CharField()
次に認証バックエンド.最初は認証ミドルウェアを置き換えようとしていたがdjangoの元の認証機能を最大限に活用しようと思うとバックエンドだけ変えた方が良さそうだった.ModelBackendのサブクラスとして実装したが,確認していない機能がほとんどなのでうまく動かない部分があるかもしれない.
project_dir/gaeutils/auth/backends.py
from django.contrib.auth.models import User from django.contrib.auth.backends import ModelBackend from google.appengine.api import users as gae_users from gaeutils.auth.models import GoogleProfile class GAEBackend(ModelBackend): def authenticate(self): gae_user = gae_users.get_current_user() if not gae_user: return None try: profile = GoogleProfile.objects.get(google_user_id=gae_user.user_id()) return profile.user except GoogleProfile.DoesNotExist: user = User.objects.create_user(gae_user.nickname(), gae_user.email()) profile = GoogleProfile(user=user, google_user_id=gae_user.user_id()) profile.save() return user
最後に実際に認証処理を呼び出すビュー.
project_dir/gaeutils/auth/views.py
from django.contrib.auth import authenticate from django.contrib.auth import login as auth_login from django.contrib.auth import logout as auth_logout from django.contrib.auth import REDIRECT_FIELD_NAME from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from google.appengine.api import users import urllib def login(request): dest = request.GET.get(REDIRECT_FIELD_NAME, '/') user = authenticate() if user is None: continued = bool(request.GET.get('continued', False)) if continued: return HttpResponseRedirect('/') query = request.GET.items() query.append(('continued', 1)) url = '%s?%s' % (reverse('login'), urllib.urlencode(query)) return HttpResponseRedirect(users.create_login_url(url)) auth_login(request, user) return HttpResponseRedirect(dest) def logout(request): dest = request.GET.get(REDIRECT_FIELD_NAME, '/') auth_logout(request) return HttpResponseRedirect(users.create_logout_url(dest))
これらを有効にするためにsettings.pyとurls.pyに追記する.
settings.py
AUTH_PROFILE_MODULE = 'gaeutils.auth.models.GoogleProfile' AUTHENTICATION_BACKENDS = ('gaeutils.auth.backends.GAEBackend', )
urls.py
urlpatterns = patterns('', # 省略 url(r'^accounts/login', auth_views.login, name='login'), url(r'^accounts/logout', auth_views.logout, name='logout'), )
これでlogin_requiredなども使える.
※このエントリは間違いを含んでいる可能性が多分にあります.ご了承ください.