今回導入した機能
-
テンプレート継承の導入(其の三で紹介済み) -
メモリ・CPU・IOの状態を確認できるように free と vmstat コマンドを追加(其の三で紹介済み) - ユーザーログイン認証
- SQLite3でのユーザーデータ管理
ファイル構成
RaspiApp
├─ static
| ├─ css
| | └─ style.css
| ├─ db
| | └─ users.sqlite
| └─ images
| └─ raspi-logo.png
├─ templates
| ├─ base.html
| ├─ get_disk.html
| ├─ get_ip_addr.html
| ├─ get_mem.html
| ├─ get_route.html
| ├─ get_socket.html
| ├─ get_temp.html
| ├─ get_vmstat.html
| ├─ index.html
| └─ login.html
└─ raspi_app.py
GitHubリポジトリ
GitHub : CannuWorks/RaspiApp
ユーザーログイン認証
- Flask-login モジュールを利用しないで実装
- sessionで管理する
認証フロー
処理プロセス
- indexでsession[login] =Trueであるかを確認し、Falseであればloginにリダイレクト
- DBに保管されているpasswordは暗号化(ハッシュ化)されているので、入力されたpasswordもget_digest()メソッドで変換して照合する必要がある
- idとpasswordを照合し、正しければsession[login] = Tureとして、Boolen値のTrueをセッションにセットする
- Trueの場合はindex、Falseの場合はloginにリダイレクトされる
- 認証が成功するとindex.html(トップページ/メニューページ)が表示される
- 各種コマンドリンクにアクセスすると、sessionsession[login] =Trueであるかを確認し、Trueであればget_xxx()メソッドを実行するが、Falseの場合、loginにリダイレクトされる。
ポイント
- 2つの条件判断
- id & passwordでユーザーを照合
- 照合に成功した場合 session[login] = True をセッションにセットする。以降の処理でそのセッションの状態を常に確認し、認証が成功していないユーザは、エンドポイントに定義したコマンドを実行できない。
コード
app.secret_key = os.urandom(21)
# Password Digest
def get_digest(password):
pwd = bytes(password, 'utf-8')
diget = hashlib.sha256(pwd).hexdigest()
return diget
# TopPage
@app.route('/')
def index():
if not session.get('login'):
return redirect(url_for('login'))
else:
return render_template('index.html')
# Login
@app.route('/login')
def login():
return render_template('login.html')
# lockin check
@app.route('/logincheck', methods=['POST'])
def logincheck():
user_id = request.form['user_id']
pwd = request.form['password']
session['username'] = user_id
# make pwd hashed by "get_digest()"" function
password = get_digest(pwd)
id_pwd_hash = get_user_data()
if user_id in id_pwd_hash:
if password == id_pwd_hash[user_id]:
session['login'] = True
else:
session['login'] = False
else:
session['login'] = False
if session['login']:
return redirect(url_for('index'))
else:
return redirect(url_for('login'))
# logout
@app.route('/logout')
def logout():
session.pop('login', None)
return redirect(url_for('index'))
login.html
<!-- main block のみ記載 -->
{% block main %}
<h2>Login Authentication</h2>
<h3>Please input User ID and Password!</h3>
<form method="POST" action="/logincheck">
<p><input placeholder="User ID" type="text" name="user_id"></p>
<p><input placeholder="Password" type="password" name="password"></p>
<p><input type="submit" value="SEND"></p>
</form>
{% endblock %}
SQLite3でのユーザーデータ管理
- データベースを作成 (ファイル名:users.sqlite)
- テーブルを作成(テーブル名:users)
id | name | password | |
---|---|---|---|
1 | use_name | user_pwd | user@ydomain.com |
import sqlite3
# DB connection
def get_user_data():
sqlite_path = 'static/db/users.sqlite'
connection = sqlite3.connect(sqlite_path)
cursor = connection.cursor()
cursor.execute('SELECT name, password FROM users')
id_pwd_hash = dict(cursor.fetchall())
connection.close()
return id_pwd_hash
まとめ
- 開発環境での実装は一旦終了
- リファクタリング的活動を実施
- Flask-loginによる認証
- BluePrintによる機能分割
- SqlalchemyでのDB接続
- nginx + uWSGIによる、Production環境のセットアップ(其の五で紹介)