「【環境構築】【テンプレート】DockerでWebアプリケーション開発環境を構築してみた!!(Nginx+Python+Flask+uWSGI+MySQL)」で記載した内容に加えて、簡易的な認証機能を実装したので紹介します(更新箇所のみを以下、記載します。)。
完成イメージ
「http://127.0.0.1:8000/」へアクセスして表示を確認すると以下、ログイン画面になります。
ログイン画面
ユーザー登録画面
パスワード再設定画面
ログイン後の表示画面
更新について
以下、「★更新」「★新規追加」のファイルを更新しました。
test
├── app
│ ├── Dockerfile
│ └── src
│ ├── app.py ★更新
│ ├── config.py
│ ├── requirements.txt ★更新
│ ├── run.py ★更新
│ ├── templates
│ │ └── list.html
│ │ └── login.html ★新規追加
│ │ └── resetting_password_cmp.html ★新規追加
│ │ └── resetting_password.html ★新規追加
│ │ └── signup.html ★新規追加
│ ├── users.py ★更新
│ └── uwsgi.ini
├── db
│ ├── init
│ │ └── createdatabase.sql ★更新
│ └── variables.env
├── docker-compose.yml
└── web
├── default.conf
└── nginx.conf
更新ソースコード
app.py
import os
from flask_login import LoginManager
import config
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# Create Flask Application
application = Flask(__name__)
# Set Config Class
application.config.from_object('config.Config')
application.config['SECRET_KEY'] = os.urandom(24)
# Set DB
db = SQLAlchemy(application)
login_manager = LoginManager()
login_manager.init_app(application)
run.py
from app import application, login_manager
from users import Users
from flask import render_template, request, redirect, make_response, Response, session
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required
from werkzeug.security import generate_password_hash, check_password_hash
from app import db
from datetime import timedelta
@login_manager.user_loader
def load_user(user_id):
return Users.query.get(int(user_id))
'''''''''''''''''
Top画面
'''''''''''''''''
@application.route('/')
def top():
return redirect('/login')
'''''''''''''''''
ログイン後画面
'''''''''''''''''
@application.route('/after')
@login_required # ログインしているユーザのみアクセス許可
def index():
users = Users.query.order_by(Users.id).all()
return render_template('list.html', users=users)
'''''''''''''''''
signup
'''''''''''''''''
@application.route('/signup', methods=['GET', 'POST'])
def signup():
if request.method == "POST":
username = request.form.get('username')
password = request.form.get('password')
# Userのインスタンスを作成
user = Users(username=username, password=generate_password_hash(password, method='sha256'), email=username)
db.session.add(user)
db.session.commit()
return redirect('login')
else:
return render_template('signup.html')
'''''''''''''''''
login
'''''''''''''''''
@application.route('/login', methods=['GET', 'POST'])
def login():
if request.method == "POST":
username = request.form.get('username')
password = request.form.get('password')
# Userテーブルからusernameに一致するユーザを取得
user = Users.query.filter_by(username=username).first()
if check_password_hash(user.password, password):
login_user(user)
return redirect('after')
else:
# 入力したユーザー名のパスワードが間違っている場合
# return "<p>パスワードが間違っています。</p>"
return Response(status=404, response="ページが見つかりません。")
else:
return render_template('login.html')
'''''''''''''''''
logout
'''''''''''''''''
@application.route('/logout')
@login_required
def logout():
logout_user()
response = make_response(redirect('/'))
return response
# 追加機能(1) ---------------- start
'''''''''''''''''
パスワード再設定
'''''''''''''''''
# パスワード再設定
# @application.route('/resetting_password')
# def resetting_pass():
# return render_template('resetting_password.html')
@application.route('/resetting_password', methods=['GET', 'POST'])
def resetting_pass():
if request.method == "POST":
email = request.form.get('email')
# emailに再設定用URLを記載したメールを送信する.
return render_template('resetting_password_cmp.html')
else:
return render_template('resetting_password.html')
'''''''''''''''''
リクエストの前処理
'''''''''''''''''
@application.before_request
def before_request():
# リクエストのたびにセッションの寿命を更新する
session.permanent = True
application.permanent_session_lifetime = timedelta(minutes=15)
session.modified = True
# 追加機能(1) ---------------- end
if __name__ == '__main__':
application.run(host='0.0.0.0', port='8000',debug=True)
users.py
from app import db
from flask_login import UserMixin
class Users(UserMixin, db.Model):
'''
Users Table Model
'''
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(255), nullable=False, unique=True)
password = db.Column(db.String(255))
email = db.Column(db.String(255))
def __init__(self,username,password,email):
self.username = username
self.password = password
self.email = email + '@' + email + '.com'
requirements.txt
Flask
uwsgi
flask-sqlalchemy
PyMySQL
flask-login
createdatabase.sql
USE app;
CREATE TABLE users(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(255),
password VARCHAR(255),
email VARCHAR(255)
);
INSERT INTO users(username,password,email) VALUES('sample','sample','sample@sample.com');
INSERT INTO users(username,password,email) VALUES('test','test','test@test.com');
INSERT INTO users(username,password,email) VALUES('app','app','app@app.com');
GRANT ALL ON app.* TO test;
login.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample login</title>
</head>
<body>
<h1>ログイン</h1>
<form method="POST">
<label for="">ユーザ名</label>
<input type="text" name="username">
<br>
<label for="">パスワード</label>
<input type="password" name="password">
<br>
<input type="submit" value="ログイン">
</form>
<a href="/resetting_password" role="button">パスワードを忘れた方はこちら</a>
<br>
<a href="/signup" role="button">ユーザー登録はこちら</a>
</body>
</html>
signup.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample signup</title>
</head>
<body>
<h1>ユーザ登録</h1>
<form method="POST">
<label for="">ユーザ名</label>
<input type="text" name="username">
<br>
<label for="">パスワード</label>
<input type="password" name="password">
<br>
<input type="submit" value="新規登録">
</form>
</body>
</html>
resetting_password.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample login</title>
</head>
<body>
<h1>パスワードを再設定する</h1>
<p>登録したメールアドレスを入力してください</p>
<form method="POST">
<label for="">メールアドレス</label>
<input type="text" name="email">
<br>
<input type="submit" value="続ける">
</form>
<a href="/" role="button">トップページに戻る</a>
</body>
</html>
resetting_password_cmp.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample login</title>
</head>
<body>
<h1>メールを確認する</h1>
<p>パスワード再設定用メールを送信しました。24時間以内にメールに記載されたリンクをクリックして手続きを行ってください。</p>
<a href="/" role="button">トップページに戻る</a>
</body>
</html>
補足事項
- ユーザー登録では、同じユーザー名の登録はできます。あくまで、簡易的な認証機能の実装になるため、各自、仕様を追加して実装ください。
- ログイン失敗時は、簡易的なページを表示しているため、各自カスタマイズしてください。
- 各画面の入力チェック(バリデーション等)の処理は実装していないため、各自実装ください。