【Flask WEBアプリ制作】google OAuthで簡単!ログイン・ログアウト処理を書く(コード例豊富)

OAuthについて

flask-danceドキュメント(googleの認証情報) をもとに書いていきます。

ログイン

HTMLとviews.py

まず、/ にアクセスしたらhome.htmlが表示される。

@bp.route('/')
def home():
    return render_template('home.html')

表示されるhome.htmlはこれ。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <ul class="nav">
        <li><a href="{{ url_for('app.home') }}">ホーム</a></li>

        {% if current_user.is_authenticated %}
        <li><a href="{{ url_for('app.logout') }}">ログアウト</a></li>
        <li><a href="{{ url_for('app.user') }}">ユーザー画面</a></li>
        {% else %}
        <li><a href="{{ url_for('app.google_login') }}">Googleログイン</a></li>
        {% endif %}
    </ul>
    <h2>ホーム画面</h2>

  </body>
</html>

{% if current_user.is_authenticated %}~{% else %}で囲まれている部分は、このユーザーがすでに認証されていたら表示される。次に「Googleログイン」のリンクをクリックすれば、def google_login(): 関数に移動する。app.google_loginとなっているのは、blueprintで登録したアプリ名がappだから。

実際に、def google_login(): に飛んできた views.pyがこちら

views.py

from flask import Blueprint, render_template, redirect, url_for
from flask_login import login_user
from loginapp.models import User
from flask_dance.contrib.google import google

bp = Blueprint('app', __name__, url_prefix='')

@bp.route('/google_login')
def google_login():
    if not google.authorized:
        return redirect(url_for("google.login")) # Googleのログイン画面にリダイレクト
    resp = google.get("/oauth2/v2/userinfo") # 認証情報を取得
    assert resp.ok, resp.text
    email = resp.json()['email']
    user = User.select_by_email(email) #emailでdb登録
    if not user:
        user = User(email=email)
        user.add_user()
    login_user(user, remember=True) #セッション情報を保存
    return render_template('welcome.html', email=email)

flask_danceのgoogleメソッドを使ってGoogleのログイン画面にリダイレクトする。email = resp.json()[‘email’] でGoogleからemailを取得。

user = User.select_by_email(email) 

これは、models.pyで定義した、Userというクラスを使ってデータベースからemailでuserを選択しているメソッドです。でも、初回はemailがまだdbに入ってませんよね。とりあえず、emailでuserを検索かけてみるってことです。その次でuserがなかったらこうするよって処理を書いてます。

if not user:
    user = User(email=email)
    user.add_user()

取得したemailをUserクラスの引数にし、userオブジェクトを作ります。そして、models.pyのメソッド add_user()を使ってuser情報を登録しています。この時、usernameとpasswordはなく、emailしかありませんが、それでも登録できるようにmodels.pyに設定を書いています。

login_user(user, remember=True) #セッション情報を保存
return render_template('welcome.html', email=email)

こうして最後にflask_loginのlogin_userメソッドでuser情報をSessionに保存。これにてログインを完了し、welcome.htmlを表示します。

models.py

from loginapp import db, login_manager
from flask_bcrypt import generate_password_hash, check_password_hash
from flask_login import UserMixin
import string
import random

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(user_id)

class User(UserMixin, db.Model):

    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), index=True, unique=True, nullable=False)
    username = db.Column(db.String(64))
    password = db.Column(db.String(128))

    # パスワードのバリデーション
    def __init__(self, email, username=None, password=None):
        self.email = email
        self.username = username
        if password is None:
            letters = string.ascii_lowercase
            password = ''.join(random.choice(letters) for _ in range(10))
        self.password = generate_password_hash(password)

    @classmethod
    def select_by_email(cls, email):
        return cls.query.filter(cls.email==email).first()
    
    def add_user(self):
        db.session.add(self)
        db.session.commit()

    def validate_password(self, password):
        return check_password_hash(self.password, password)

__init__.py

__init__.pyはドキュメント通りに書きます

ログアウト

from flask import Blueprint, redirect
from flask_login import login_required, logout_user
from flask_dance.contrib.google import google
from loginapp import google_blueprint #initファイルからインポート

@bp.route('/logout')
@login_required
def logout():
    if google.authorized:
        token = google_blueprint.token['access_token']
        resp = google.post(
            "https://accounts.google.com/o/oauth2/revoke",
            params={"token": token},
            headers={"Content-Type": "application/x-www-form-urlencoded"}
        )
        assert resp.ok,resp.text
        del google_blueprint.token # token削除
    logout_user()
    return redirect(url_for('app.home'))

home.htmlのログアウトをクリックしたらlogout関数に移ります。ここは、ほぼドキュメント通りです。最後の二行で flask_login のlogout_user()でログアウトします。最後にhome関数に遷移します。