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関数に遷移します。