Django REST × React で Google ログインボタンを作成する際、
python social auth の各メソッドに関してしっかり理解する必要があったためまとめてみました
ggってもほとんど情報が出てこなかったので、たぶん使ってる人ほとんどいないっぽいですので、
誰の役にも立たなさそうですが、、、
各メソッドの詳細
create_user
def create_user(strategy, details, backend, user=None, *args, **kwargs):
if user:
return {'is_new': False}
fields = {name: kwargs.get(name, details.get(name))
for name in backend.setting('USER_FIELDS', USER_FIELDS)}
if not fields:
return
return {
'is_new': True,
'user': strategy.create_user(**fields)
}
- ユーザが見つからなかった場合作成するメソッド
- 引数にuserが存在している場合
- is_new : False(つまり、新規作成ではない)としてreturnして終了
- fields変数に値を入力
- おそらく、settings.pyのUSER_FIELDSのリストを取ってきて、そこで指定されているものをforで取得している
- デフォルトはusernameとemail user.pyの一番上で初期化されている
- 変数が空の場合何も返さず終了
- fields変数を元にdjango内のcreate_userメソッドを実行し、作成されたuserインスタンスを返す
social_user
def social_user(backend, uid, user=None, *args, **kwargs):
provider = backend.name
social = backend.strategy.storage.user.get_social_auth(provider, uid)
if social:
if user and social.user != user:
raise AuthAlreadyAssociated(backend)
elif not user:
user = social.user
return {'social': social,
'user': user,
'is_new': user is None,
'new_association': social is None}
- 送られてきたアカウントがすでにdjangoアプリ上に存在するかどうかを検証するメソッド
- provider : 認証バックエンドの名前を指定
- social : backendのget_social_authメソッドを実行してユーザデータを引き抜いてると思う
- social が取得できた場合
- 引数のuserが存在していて かつ 引数のuserとsocial.userが一致しない場合
- ユーザーがすでに存在していますのエラーを発砲
- 引数のuserが存在していない場合
- social.user を user 変数に入れる
- 引数のuserが存在していて かつ 引数のuserとsocial.userが一致しない場合
- social, user, is_new, new_association を返す
- is_new: user is None : 引数のuserが存在しなかった場合Trueとして返す
- new_association: social is None : socialに値が入らなかった場合Trueとして返す
associate_user
def associate_user(backend, uid, user=None, social=None, *args, **kwargs):
if user and not social:
try:
social = backend.strategy.storage.user.create_social_auth(
user, uid, backend.name
)
except Exception as err:
if not backend.strategy.storage.is_integrity_error(err):
raise
# Protect for possible race condition, those bastard with FTL
# clicking capabilities, check issue #131:
# https://github.com/omab/django-social-auth/issues/131
result = social_user(backend, uid, user, *args, **kwargs)
# Check if matching social auth really exists. In case it does
# not, the integrity error probably had different cause than
# existing entry and should not be hidden.
if not result['social']:
raise
return result
else:
return {'social': social,
'user': social.user,
'new_association': True}
- ソーシャルアカウントと、サイト内のユーザアカウントを結びつけるレコードを作成するメソッド
- 引数のuserが存在していて かつ socialは存在していない場合
- social変数に,user情報をもとにcreate_social_authメソッドを実行した値を入れる
- ダメだった場合エラーを発砲
user_detail
def user_details(strategy, details, backend, user=None, *args, **kwargs):
"""Update user details using data from provider."""
if not user:
return
changed = False # flag to track changes
# Default protected user fields (username, id, pk and email) can be ignored
# by setting the SOCIAL_AUTH_NO_DEFAULT_PROTECTED_USER_FIELDS to True
if strategy.setting('NO_DEFAULT_PROTECTED_USER_FIELDS') is True:
protected = ()
else:
protected = ('username', 'id', 'pk', 'email', 'password',
'is_active', 'is_staff', 'is_superuser',)
protected = protected + tuple(strategy.setting('PROTECTED_USER_FIELDS', []))
# Update user model attributes with the new data sent by the current
# provider. Update on some attributes is disabled by default, for
# example username and id fields. It's also possible to disable update
# on fields defined in SOCIAL_AUTH_PROTECTED_USER_FIELDS.
field_mapping = strategy.setting('USER_FIELD_MAPPING', {}, backend)
for name, value in details.items():
# Convert to existing user field if mapping exists
name = field_mapping.get(name, name)
if value is None or not hasattr(user, name) or name in protected:
continue
current_value = getattr(user, name, None)
if current_value == value:
continue
immutable_fields = tuple(strategy.setting('IMMUTABLE_USER_FIELDS', []))
if name in immutable_fields and current_value:
continue
changed = True
setattr(user, name, value)
if changed:
strategy.storage.user.changed(user)
- ソーシャルアカウントに変更点があった場合変更点を統合するメソッド
- user が None だったらreturnされて実行されない
- user field の保護設定
- NO_DEFAULT_PROTECTED_USER_FIELDS : デフォルトで
False
で、usermodelの特定のフィールドに変更が起きないように保護できる - NO_DEFAULT_PROTECTED_USER_FIELDS = True を settings.py に入力すると、逆に保護を解除できる(つまり、Socialアカウント側に設定を寄せる)
- SOCIAL_AUTH_PROTECTED_USER_FIELDS = ('some', 'thing', 'else') として設定すれば、保護したいフィールドを追加できる
- NO_DEFAULT_PROTECTED_USER_FIELDS : デフォルトで
出てくる謎の引数strategy
, backend
, storage
について
strategy
おそらく、今回の場合Djangoのこと
strategy.setting で、settings.py の中の設定を参照する
strategy.create_user() で、Django内のcreate_userメソッドを実行する
backend
認証プロバイダー(今回の場合Google)のこと
詳細が不明だがbackend.something
と出てきたら、GoogleTokenの中身を参照しているはず
storage
おそらく、認証プロバイダーのアカウントによって作成された情報が格納されたDBのことだと思う
多分、requestボディに入っているtokenIdをデコードして、username,emailとかを一時的に保存しているのか
もしかしたら、直接Google(twitter,facebook,etc)のデータベースにアクセスしているのかもしれない
social = backend.strategy.storage.user.get_social_auth(provider, uid)
return user = social.user
user_detailsメソッドに↑のような処理があるが、
これは引数のuser
とstorageから引き出したuser情報を比較して、変更が見つかった場合、
storageから引き出した内容で上書きしてuserオブジェクトを返す処理となっている