見出し画像

django で LINEログイン を実装した

djangoで作ったWEBサービスに、LINEログインを実装しました。公式以外のドキュメントが非常に少なく、時間がかかってしまったので、サンプルコードを記載しておきます。(セキュリティ等担保するものではありませんので、自己責任で活用ください。)

環境

django:2.2.3
Python 3.7.7
Heroku

実装できたこと

①djangoで作成した、自分のWEBサービスにLINEログインを活用して、ユーザーの作成、ログインを実装
②LINEの表示名、メールアドレスを取得し、自前のユーザーモデルに反映

実際にLINEログインを実装したサイトです。
保育学生の就活を支援する【ぴたカフェオンライン】|求人票や園見学情報

参考にしたサイト

PythonでLINEログインを実装
Flaskで実装されていたため、こちらを元にdjango用に改変させていただきました。

手順

①LINE DevelopersでLINEログインのチャンネルを作成
②各種設定、トークン、IDを取得
③ログインの処理を記載

今回は①②は参考先のサイト、紹介されているリンク先にも記載されているので省略します。ユーザーモデルにメールアドレスを利用している場合等は、②において、メールアドレスの取得申請もしておきましょう。

遷移フローとしては、
ログイン画面 → LINEログインの確認画面 → リダイレクト画面
となります。

djangoのコード

アプリ名:lines としています。

~settings.py~

LINE_CHANNEL_SECRET = os.environ.get("LINE_CHANNEL_SECRET")
LINE_REDIRECT_URL = "https://www.xxx.xxx/line_login/"
~views.py~

import json
from django.shortcuts import render
from django.views import generic
from accounts.models import User
from django.conf import settings
from django.contrib.auth import login, authenticate
from django.contrib import messages

import requests
import jwt


LINE_CHANNEL_ID = "XXX" # 自身のLINEチャンネルIDを入力
LINE_CHANNEL_SECRET = settings.LINE_CHANNEL_SECRET
REDIRECT_URL = settings.LINE_REDIRECT_URL

# ログインボタンをおく画面
class LineEnterView(generic.TemplateView):
   template_name = 'lines/enter.html'

   def get_context_data(self, **kwargs):
       context = super().get_context_data(**kwargs)
       context['channel_id'] = LINE_CHANNEL_ID
       context['redirect_url'] = REDIRECT_URL
       context['random_state'] = "line1216" # 参照元ママ
       return context


# LINEloginのリダイレクト先
def line_login(request):
   context = {}
   # 認可コードを取得する
   request_code = request.GET.get("code")
   uri_access_token = "https://api.line.me/oauth2/v2.1/token"
   headers = {"Content-Type": "application/x-www-form-urlencoded"}
   data_params = {
       "grant_type": "authorization_code",
       "code": request_code,
       "redirect_uri": REDIRECT_URL,
       "client_id": LINE_CHANNEL_ID,
       "client_secret": LINE_CHANNEL_SECRET
   }

   # トークンを取得するためにリクエストを送る
   response_post = requests.post(uri_access_token, headers=headers, data=data_params)

   # 今回は"id_token"のみを使用する
   line_id_token = json.loads(response_post.text)["id_token"]

   # ペイロード部分をデコードすることで、ユーザ情報を取得する
   user_profile = jwt.decode(line_id_token,
                             LINE_CHANNEL_SECRET,
                             audience=LINE_CHANNEL_ID,
                             issuer='https://access.line.me',
                             algorithms=['HS256'])

   # LINE登録のユーザー情報を表示する場合は、contextに追加しておく
   context["user_profile"]=user_profile

   # LINEで取得した情報と、ユーザーデータベースを付け合わせ
   line_user, created = User.objects.get_or_create(email=user_profile["email"])

   if (created):
       line_user.username = user_profile['name']  # 例:ユーザーネームにLINEネームを反映
       line_user.save()
       messages.success(request, 'ユーザーを作成しました。ユーザー名:{}'.format(line_user.username))

   else:
       messages.warning(request, 'ログインしました。{}'.format(line_user.get_full_name()))

   # そのままログインさせる
   login(request, line_user, backend='django.contrib.auth.backends.ModelBackend')

   return render(request, "lines/line_success.html", context)
   

メールアドレスで、LINEのユーザーと、自前サービスのユーザーを付け合わせしています。ユーザーが未登録であれば新規作成、登録済みであれば、該当のユーザーを取得します。

ユーザー関連の処理を行いたい場合は、ユーザー取得後の処理に追加してください。取得できる情報は、IDトークンからプロフィール情報とメールアドレスを取得するに記載があります。

テンプレートのサンプルも、要所のみ記載します。

~lines/enter.html~
{% extends 'lines/base.html' %}

{% block content %}

<a href="https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id={{ channel_id }}&redirect_uri={{ redirect_url }}&state={{ random_state }}&bot_prompt=aggressive&scope=profile%20openid%20email">
<img src="https://res.cloudinary.com/XXX/btn_login_base_p8cawe.png"></a>

{% endblock %}

a タグのリンクがログインのためのリクエストボタンです。contextに入力していた変数が利用されます。

img はLINEログインボタン デザインガイドライン からダウンロードしてください。上記のコードはcloudinaryに設置している例です。

line_success.html は特に記載しませんが、必要な情報があれば、contextに追記しましょう。




スタートアップ支援と、社内スタートアップをしながら、実務未経験から独学でプログラミング勉強中。主にpython。スクレイピング、機械学習から始めて、最近はDjangoを学習し、WEBサービス作成中。独学されている初心者の方向けに、技術の記事を中心に書いていきます。