DjangoでGoogle認証を行う

# DjangoでGoogle認証を行う

Djangoのログインを独自のものではなくGoogleのアカウントを使ってやります。利用するモジュールのReadMeを読んでもぱっとわからなかったのでメモ。

## 使用するもの
バージョンは私が利用したものです。

* Python: 2.7.8
  * Django: 1.7.7
  * python-social-auth: 0.2.3
    * その他上記のライブラリの依存関係にあるもの

## 手順
`python manage.py runserver`が実行できる状態であると仮定しています。
また、google appは作成済みでIDやsecret keyは取得しておいてください。

まずは`python-social-auth`をインストール
`pip install python-social-auth`

次に`settings.py`とurls.pyに設定を書き込みます。

`project/setting.py`に以下を追記

```
INSTALLED_APPS = (
   ...
   'social.apps.django_app.default',
   ...
)

TEMPLATE_CONTEXT_PROCESSORS = (
   'django.contrib.auth.context_processors.auth',
   'django.core.context_processors.debug',
   'django.core.context_processors.i18n',
   'django.core.context_processors.media',
   'django.core.context_processors.static',
   'django.core.context_processors.tz',
   'django.contrib.messages.context_processors.messages',
   'social.apps.django_app.context_processors.backends',
   'social.apps.django_app.context_processors.login_redirect',
)

AUTHENTICATION_BACKENDS = (
   'social.backends.facebook.FacebookOAuth2',
   'social.backends.google.GoogleOAuth2',
   'social.backends.twitter.TwitterOAuth',
   'django.contrib.auth.backends.ModelBackend',
)

SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'your secret id'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'your secret key'

```

`project_name/urls.py`

```
urlpatterns = patterns('',
...
url('', include('social.apps.django_app.urls', namespace='social')),
url('', include('django.contrib.auth.urls', namespace='auth')),
...
)
```

次にtemplateの編集を行っていきます。
今回は管理画面のログイン・ユーザー登録をGoogle認証に置き換えます。

まずは管理画面のログイン画面を作成して既存のものにオーバーライドします。

`templates/admin/login.html`を作成し、[こちらのファイル](https://github.com/django/django/blob/master/django/contrib/admin/templates/admin/login.html)をコピペしてください。コピペしたファイル内のcontentブロックを書き換えます。(本来はlogin.html全体ではなく、部分的にオーバーライドするらしいのですが、わからないので全体をオーバーライドしています...)

```
{% block content %}
  <center>
  {% if user and not user.is_anonymous %}
     <h1><a href="{% url 'auth:logout' %}?next={{ request.path }}">Logout</a></h1>
  {% else %}
      <h1><a href="{% url 'social:begin' 'google-oauth2' %}?next={% url 'admin:index' %}">Login with Google</a></h1>
  {% endif %}
      </center>
{% endblock %}
```

手順は以上です。それでは実際に実行して確認してみてください。
以下、躓きやすい点をリストアップしました。

### login.htmlをオーバーライドできない
* settings.pyのTEMPLATE_DIRSを確認
    * settings.pyにTEMPLATE_DIRSを設定してプロジェクトのtemplates/admin内にlogin.htmlを置くことでオーバーライド出来ました。
    * `TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]`

### google認証でInvalid ~ と出る

* たいていはリダイレクト先のURL登録ミス(私)
* メールアドレスはgoogle appに登録したか？
* そもそもsecret keyなどの情報は合っているか？

以上になります。作成してから書いたので抜け漏れがあるかもしれません。何か気づいた点があれば教えていただけると幸いです。

## その他
### メールアドレスでバリデーションする

settings.pyに以下を追加すればOK
`SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_EMAILS = ['email address']`
メールアドレスではなくメールアドレスのドメインでバリデーションする場合は以下を追加
`SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS = ['domain']`

### デフォルトでstaff, superuserを有効化する

adminにソーシャルログインして何も見られないのはつらいのでis_staffとis_superuserを最初から有効化したかったので、pipelineに独自で作成した関数を追加してやります。今回は作成したユーザーのis_staff, is_superuserを書き換えてやります。

`project_name/custome_pipeline.py`

```
def set_superuser(user, *args, **kwargs):
    user.is_staff = True
    user.is_superuser = True
    user.save()
```

あとはsettings.pyに以下を追加してやります。create_userのあとに作成した処理を差し込むのがポイント

```
SOCIAL_AUTH_PIPELINE = (
    'social.pipeline.social_auth.social_details',
    'social.pipeline.social_auth.social_uid',
    'social.pipeline.social_auth.auth_allowed',
    'social.pipeline.social_auth.social_user',
    'social.pipeline.user.get_username',
    'social.pipeline.user.create_user',
    'project_name.custom_pipeline.set_superuser',  # 用意した関数へのパス
    'social.pipeline.social_auth.associate_user',
    'social.pipeline.social_auth.load_extra_data',
    'social.pipeline.user.user_details'
)

```

## 参考
* http://www.artandlogic.com/blog/2014/04/tutorial-adding-facebooktwittergoogle-authentication-to-a-django-application/
* http://python-social-auth.readthedocs.org/en/latest/pipeline.html
* http://python-social-auth.readthedocs.org/en/latest/configuration/settings.html