Flaskを使用したLINEログイン連携メモ

* Flaskを使用したLINEログイン連携についてメモする。
  * [Google](https://qiita.com/KWS_0901/items/28066892d0811e571796)、[Facebook](https://qiita.com/KWS_0901/items/e9b0f81464370ffed3cd)で試したログイン連携のLINE版。

## 大まかな処理の流れ

1. LINEへ認可リクエスト(Authorization Request)を行う。

2. ユーザー認証/同意を行い、認可レスポンスを受け取る。

3. 認可レスポンスを使ってトークンリクエストを行う。

4. 取得したアクセストークンを使用してユーザープロフィールを取得する。

   

## 事前準備

* [LINE Developersコンソール](https://developers.line.biz/console/)からLINEログインチャネルを作成する。
  * クライアントID(チャネルID)/クライアントシークレット(チャネルシークレット)を取得する。
  * コールバックURL(リダイレクトURL)にhttp://localhost:5000/callbackを入力する。
* PythonやFlaskのインストールは実施済みであるものとする。




## 実装

* 認可リクエスト ~ ユーザープロフィール取得までのコード。
  * エラーハンドリングなど非対応。

```python
import hashlib
from flask import Flask, request, redirect, session
import urllib.request
import urllib.parse
import json
import base64
from pprint import pprint
import os

# クライアント情報
# Channel ID
client_id = "<YOUR_CHANNEL_ID>"
# Channel Secret
client_secret = "<YOUR_CHANNEL_SECRET>"
# Callback URL
redirect_uri = 'http://localhost:5000/callback'

# LINE エンドポイント
authorization_url = 'https://access.line.me/dialog/oauth/weblogin'
token_url = 'https://api.line.me/v2/oauth/accessToken'
user_info_url = 'https://api.line.me/v2/profile'

app = Flask(__name__)
app.secret_key = 'session_key'

# 1.LINEへ認可リクエスト(Authorization Request)を行う。
# ユーザーに認証と認可を要求する:https://developers.line.biz/ja/docs/line-login/integrate-line-login-v2/#making-an-authorization-request
@app.route("/login")
def login():
    # ステート生成
    state = hashlib.sha256(os.urandom(32)).hexdigest()
    session['state'] = state
    # 認可リクエスト
    return redirect(authorization_url+'?{}'.format(urllib.parse.urlencode({
        'client_id': client_id,
        'redirect_uri': redirect_uri,
        'state': state,
        'response_type': 'code'
    })))


# 認可リクエスト受信 → トークンリクエスト → ユーザープロフィールリクエスト
@app.route("/callback")
def callback():
    # 2. ユーザー認証/同意を行い、認可レスポンスを受け取る。
    # 認可コードを受け取る:https://developers.line.biz/ja/docs/line-login/integrate-line-login-v2/#receiving-the-authorization-code
    state = request.args.get('state')
    if state != session['state']:
        print("invalid_redirect")
    code = request.args.get('code')
    
    # 3. 認可レスポンスを使ってトークンリクエストを行う。
    # ウェブアプリでアクセストークンを取得する:https://developers.line.biz/ja/docs/line-login/integrate-line-login-v2/#get-access-token
    body = urllib.parse.urlencode({
        'code': code,
        'client_id': client_id,
        'client_secret': client_secret,
        'redirect_uri': redirect_uri,
        'grant_type': 'authorization_code'
    }).encode('utf-8')
    req, res = '', ''
    req = urllib.request.Request(token_url)
    with urllib.request.urlopen(req, data=body) as f:
        res = f.read()
    access_token = json.loads(res)['access_token']
	# 4. 取得したアクセストークンを使用してユーザープロフィールを取得する。
    # ユーザープロフィールを取得する:https://developers.line.biz/ja/docs/line-login/managing-users/#get-profile
    headers = {
        'Authorization': 'Bearer ' + access_token
    }
    req = urllib.request.Request(user_info_url, headers=headers, method='GET')
    with urllib.request.urlopen(req) as f:
        res = f.read()

    return json.loads(res)


if __name__ == "__main__":
    app.run(debug=True)


```



## 参考情報

* [ウェブアプリにLINEログインを組み込む（LINEログイン v2.0）](https://developers.line.biz/ja/docs/line-login/integrate-line-login-v2/)