2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめてのアドベントカレンダーAdvent Calendar 2023

Day 16

Django(RDF)のGoogleソーシャルログインの覚書

Last updated at Posted at 2023-12-24

やりたいこと

バックエンドとフロントエンドを分離して、API経由でソーシャルログインを実現したいのでごちゃごちゃやっていて、色々見えてきたので、自分のメモとして書き置きしておきます。

使用したモジュール

  • dj-rest-auth

基本的には、公式ドキュメントの通りにやっておけば問題ないかと思います。

setting.pyの詳細な設定はここでは省略してます。

Googleの認証方法2つのやり方?

2023年12月調べたところ、Googleの認証方法には2通りあり

  • Authorization Code Grant
  • Implicit Grant
    があるらしく、これによってViewの書き方が一行変わります。

GPTによると

OAuth 2.0の認証フローについては、一般的にAuthorization Code Grantが推奨されています。
Implicit Grantフローは、以前はブラウザベースのアプリケーションで使用されていましたが、セキュリティ上の理由から現在は推奨されていません。特に、Implicit Grantフローではアクセストークンがブラウザを通じて直接クライアントに送信されるため、トークンが漏洩するリスクがあります。
一方、Authorization Code Grantフローでは、認証コードがクライアントに送信され、その後サーバーサイドでアクセストークンと交換されます。これにより、アクセストークンが公開されるリスクが軽減されます。

とのことなので、Authorization Code Grantを採用していきたいと思います。

実装方針

認証フローを何も知らないと、やってて訳わからなくなると思うので、一旦以下の神記事を読むことをお勧めします。

神記事の通りに実装する方法を書いていきます。
具体的なコードは下にまとめとくので、適時実装してください。

1. ユーザーにリンクを踏ませる

画像
(https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be より拝借)

まずは、ユーザーにリンクを踏ませる必要があるので、以下のリンクにアクセスしてもらいます。

https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=&prompt=consent&response_type=code&client_id=&scope=openid%20email%20profile&access_type=offline

ただし、ここで、

  • CALLBACK_URL_YOU_SET_ON_GOOGLE
  • YOUR CLIENT ID
    が必要となるので、GCPにアクセスして、クライアントIDを入手して、コールバックURLを設定してください。ここら辺は、いっぱい記事があるので省略します。

コールバックURLっては、googleでログインした後に飛ばされるページのことです。

飛ばされるページは以下のViewを設定して、そこに飛ばせば良いです。

View

from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from dj_rest_auth.registration.views import SocialLoginView


class GoogleLoginView(SocialLoginView):
    adapter_class = GoogleOAuth2Adapter
    client_class = OAuth2Client
    callback_url = "http://127.0.0.1:8000/api/social/login/google/"

ちなみに、
callback_url = ''は、Authorization Code Grantの場合必須になります。

2. リンクを踏んで遷移する

画像
(https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be より拝借)

あとは、dj-rest-authがよしなにやってくれます。

さっきのリンクを踏んでみて、ログインしてみましょう。
すると

スクリーンショット 2023-12-25 7.12.41.png

のような感じになると思います。

ここで、codeが上にあると思うので、それをコピペしてPOSTすれば終わりです!!!!
っと言いたいところですが、URLエンコードという概念があり、URL経由でコピペされたものはエンコードされてしまします。
なので、残念ですが、このやり方で確認したい場合、モジュールのコードを直いじりする必要があります。

lib/python3.10/site-packages/allauth/socialaccount/providers/oauth2/client.py

from urllib.parse import unquote

    def get_access_token(self, code):
        data = {
            "redirect_uri": self.callback_url,
            "grant_type": "authorization_code",
            "code": unquote(code), #unquoteを追加
        }

っとモジュールのソースコードを変更してあげれば、無事いつものソーシャルログインのように自動でユーザーが作られ、アクセストークンとリフレッシュトークンが発行されるはずです。

また、DRFのView経由ではなく、curlを使った場合

curl -d "client_id=*****.apps.googleusercontent.com" -d "client_secret=*****" -d "redirect_uri=http://127.0.0.1:8000/api/social/login/google/" -d "grant_type=authorization_code" -d "code=*****" https://oauth2.googleapis.com/token

でいけると思います。

沼ったところ

  • ソーシャルログイン自体を理解していなかった
    なんか適当にやってたけど、ちゃんとOAuthの概念を理解した方が結果的に早かった
  • モジュールのバージョン
    dj-rest-authのモジュールを昔のバーションで固定で入れてたので、URLが変わっていることに気が付かなかった
  • URLエンコード
    以下のエラーに死ぬほど悩まされた。
  File "/Users/****/next-drf-blog-auth-book/env/lib/python3.10/site-packages/allauth/socialaccount/providers/oauth2/client.py", line 109, in get_access_token
    raise OAuth2Error("Error retrieving access token: %s" % resp.content)
allauth.socialaccount.providers.oauth2.client.OAuth2Error: Error retrieving access token: b'{\n  "error": "invalid_grant",\n  "error_description": "Malformed auth code."\n}'

上記の通り、URLエンコードの概念を知らなかったので、URLのコピペでは認証コードが変換されてるから、そりゃ不正なコードっていいますわな。色々疑ってすまんかったな。ワイが無知やったで。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?