在 Web 應用程式開發中,使用者認證是不可或缺的一環。本文將以 Flask 框架為例,示範如何實作不同方式的使用者認證機制,包含簡易的 Session-Based 認證、使用 Flask-Login 擴充套件,以及整合第三方服務。Session-Based 認證的核心概念是將使用者資訊儲存在伺服器端的 Session 中,並透過瀏覽器 Cookie 維護狀態。Flask-Login 則提供更簡潔、安全的方式管理使用者登入狀態,並支援「記住我」等功能。此外,文章也將探討如何使用第三方服務,例如 Google、Facebook 等進行認證,以提升使用者經驗。程式碼範例涵蓋使用者模型建立、表單設計、路由設定、檢視函式撰寫、範本渲染等關鍵步驟,並深入解析 Flask-Login 的運作機制,幫助讀者快速掌握 Flask 應用程式使用者認證的實務技巧。
使用者認證
簡易的 Session-Based 認證
當使用者首次登入時,其詳細資訊會被儲存在伺服器端的 Session 中,並在瀏覽器中儲存 Cookie。接下來的請求將使用此 Session 進行驗證。
認證方法
本章節將介紹多種認證方法,包括:
- 簡易的 Session-Based 認證
- 使用 Flask-Login 擴充套件進行認證
- 使用第三方服務(如 Facebook、Google、Twitter、LDAP)進行認證
簡易的 Session-Based 認證實作
首先,我們需要建立一個使用者模型,並實作登入邏輯,將使用者資訊儲存在 Session 中。
from flask import session
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and user.password == password:
session['user_id'] = user.id
return '登入成功'
return '登入失敗', 401
內容解密:
- 使用者登入時,驗證其帳號密碼。
- 若驗證成功,將使用者 ID 儲存在 Session 中。
在Flask中進行簡單的會話式身份驗證
在開發Web應用程式時,身份驗證是一個非常重要的功能。Flask作為一個輕量級的Web框架,提供了足夠的靈活性來實作各種身份驗證機制。在本章中,我們將探討如何在Flask應用程式中實作一個簡單的會話式身份驗證系統。
準備工作
首先,我們需要組態Flask應用程式以使用SQLAlchemy和WTForms擴充套件。這兩個擴充套件將幫助我們處理資料函式庫操作和表單驗證。
步驟1:建立使用者模型
我們首先需要建立一個使用者模型來儲存使用者的詳細資訊。在flask_authentication/my_app/auth/models.py檔案中,我們定義了User模型,如下所示:
from werkzeug.security import generate_password_hash, check_password_hash
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import InputRequired, EqualTo
from my_app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(100))
pwdhash = db.Column(db.String())
def __init__(self, username, password):
self.username = username
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
步驟2:建立註冊和登入表單
接下來,我們需要建立兩個表單:RegistrationForm和LoginForm。這些表單將用於處理使用者註冊和登入。
class RegistrationForm(FlaskForm):
username = StringField('Username', [InputRequired()])
password = PasswordField(
'Password', [
InputRequired(), EqualTo('confirm',
message='Passwords must match')
]
)
confirm = PasswordField('Confirm Password',
[InputRequired()])
class LoginForm(FlaskForm):
username = StringField('Username', [InputRequired()])
password = PasswordField('Password', [InputRequired()])
實作註冊和登入功能
步驟3:建立檢視函式
現在,我們需要建立檢視函式來處理使用者的註冊和登入請求。在flask_authentication/my_app/auth/views.py檔案中,我們定義了相應的檢視函式。
from flask import request, render_template, flash, redirect, url_for, session, Blueprint
from my_app import app, db
from my_app.auth.models import User, RegistrationForm, LoginForm
auth = Blueprint('auth', __name__)
@auth.route('/register', methods=['GET', 'POST'])
def register():
# 處理註冊邏輯
if session.get('username'):
flash('Your are already logged in.', 'info')
return redirect(url_for('auth.home'))
form = RegistrationForm()
if form.validate_on_submit():
# 檢查使用者名稱是否存在
existing_username = User.query.filter(User.username.like('%' + form.username.data + '%')).first()
if existing_username:
flash('This username has been already taken. Try another one.', 'warning')
return render_template('register.html', form=form)
# 建立新使用者
user = User(form.username.data, form.password.data)
db.session.add(user)
db.session.commit()
flash('You are now registered. Please login.', 'success')
return redirect(url_for('auth.login'))
if form.errors:
flash(form.errors, 'danger')
return render_template('register.html', form=form)
@auth.route('/login', methods=['GET', 'POST'])
def login():
# 處理登入邏輯
form = LoginForm()
if form.validate_on_submit():
existing_user = User.query.filter_by(username=form.username.data).first()
if not (existing_user and existing_user.check_password(form.password.data)):
flash('Invalid username or password. Please try again.', 'danger')
return render_template('login.html', form=form)
session['username'] = form.username.data
flash('You have successfully logged in.', 'success')
return redirect(url_for('auth.home'))
if form.errors:
flash(form.errors, 'danger')
return render_template('login.html', form=form)
@auth.route('/logout')
def logout():
# 處理登出邏輯
if 'username' in session:
session.pop('username')
flash('You have successfully logged out.', 'success')
return redirect(url_for('auth.home'))
範本實作
最後,我們需要建立相應的範本來渲染註冊和登入頁面。這些範本將使用Flask的Jinja2範本引擎來渲染。
首頁範本(home.html)
{% extends 'base.html' %}
{% block container %}
<h1>Welcome to the Authentication Demo</h1>
{% if session.username %}
<h3>Hey {{ session.username }}!!</h3>
<a href="{{ url_for('auth.logout') }}">Click here to logout</a>
{% else %}
Click here to <a href="{{ url_for('auth.login') }}">login</a> or <a href="{{ url_for('auth.register') }}">register</a>
{% endif %}
{% endblock %}
註冊頁面範本(register.html)
{% extends 'home.html' %}
{% block container %}
<div class="top-pad">
<form method="POST" action="{{ url_for('auth.register') }}" role="form">
{{ form.csrf_token }}
<div class="form-group">{{ form.username.label }}: {{ form.username() }}</div>
<div class="form-group">{{ form.password.label }}: {{ form.password() }}</div>
<div class="form-group">{{ form.confirm.label }}: {{ form.confirm() }}</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
{% endblock %}
登入頁面範本(login.html)
{% extends 'home.html' %}
{% block container %}
<div class="top-pad">
<form method="POST" action="{{ url_for('auth.login') }}" role="form">
{{ form.csrf_token }}
<div class="form-group">{{ form.username.label }}: {{ form.username() }}</div>
<div class="form-group">{{ form.password.label }}: {{ form.password() }}</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
{% endblock %}
內容解密:
上述程式碼實作了一個簡單的會話式身份驗證系統。首先,使用者模型被定義用於儲存使用者資訊。然後,註冊和登入表單被建立用於處理使用者輸入。接著,檢視函式被定義用於處理註冊、登入和登出請求。最後,相應的範本被建立用於渲染註冊和登入頁面。整個系統透過Flask的會話機制來管理使用者的登入狀態。
使用Flask-Login擴充功能進行身份驗證
在前面的章節中,我們學習瞭如何自行實作根據會話的身份驗證。Flask-Login是一個流行的擴充功能,可以有效地處理許多相同的事情,從而避免重複造輪子。此外,Flask-Login不會將我們繫結到任何特定的資料函式庫,也不會限制我們使用特定的欄位或方法進行身份驗證。它還可以處理「記住我」功能、帳戶還原功能等。在本章節中,我們將瞭解如何將Flask-Login與我們的應用程式一起使用。
準備工作
首先,修改前一個章節中建立的應用程式,以適應Flask-Login擴充功能所做的更改。在此之前,我們需要使用以下命令安裝擴充功能:
$ pip install Flask-Login
操作步驟
按照以下步驟瞭解如何將Flask-Login整合到Flask應用程式中:
- 組態應用程式
首先,修改應用程式的組態(位於
flask_authentication/my_app/__init__.py),如下所示:
from flask_login import LoginManager
其他應用程式組態
login_manager = LoginManager() login_manager.init_app(app) login_manager.login_view = ‘auth.login’
在上述程式碼片段中,我們從擴充功能匯入`LoginManager`類別後建立了一個物件。然後,我們使用`init_app()`組態了`app`物件以與`LoginManager`一起使用。這裡演示了一個基本且必要的組態,即`login_view`,它指向登入請求的檢視處理程式。
2. **修改User模型**
`Flask-Login`要求在`User`模型/類別中新增一些額外的方法,如下所示(位於`my_app/auth/models.py`):
```python
@property
def is_authenticated(self):
return True
@property
def is_active(self):
return True
@property
def is_anonymous(self):
return False
def get_id(self):
return str(self.id)
內容解密:
is_authenticated()屬性傳回True,表示使用者已透過身份驗證。is_active()屬性傳回True,表示使用者帳戶是活躍的。is_anonymous()屬性傳回False,表示使用者不是匿名使用者。get_id()方法傳回使用者的唯一ID,這應該是一個Unicode值。
- 修改檢視
對
my_app/auth/views.py中的檢視進行以下更改:
from flask import g from flask_login import current_user, login_user, logout_user, login_required from my_app import login_manager
@login_manager.user_loader def load_user(id): return User.query.get(int(id))
@auth.before_request def get_current_user(): g.user = current_user
#### 內容解密:
- `@login_manager.user_loader`裝飾器用於指定一個函式來載入使用者物件。
- `@auth.before_request`裝飾器表示在每次接收到請求之前都會呼叫該方法,用於取得當前使用者。
4. **登入和登出邏輯**
```python
@auth.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
flash('您已經登入。', 'info')
return redirect(url_for('auth.home'))
# 省略其他程式碼...
@auth.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('auth.home'))
內容解密:
- 在
login()函式中,我們檢查當前使用者是否已經透過身份驗證。如果是,則直接跳轉到首頁。 - 使用
login_user()方法登入使用者,並處理相關的會話活動。 logout()函式使用logout_user()方法清理當前使用者的會話,從而登出使用者。
工作原理
本章節的示範與前一個章節「建立簡單的根據會話的身份驗證」的工作原理相同,只是實作方式有所不同,但最終結果保持一致。
額外資訊
Flask-Login擴充功能使實作「記住我」功能變得非常簡單。只需在呼叫login_user()方法時傳遞remember=True即可。這將在使用者的電腦上儲存一個cookie,Flask-Login將使用它在會話活動時自動登入使用者。建議您嘗試自行實作此功能。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Flask 應用程式使用者認證實作
package "機器學習流程" {
package "資料處理" {
component [資料收集] as collect
component [資料清洗] as clean
component [特徵工程] as feature
}
package "模型訓練" {
component [模型選擇] as select
component [超參數調優] as tune
component [交叉驗證] as cv
}
package "評估部署" {
component [模型評估] as eval
component [模型部署] as deploy
component [監控維護] as monitor
}
}
collect --> clean : 原始資料
clean --> feature : 乾淨資料
feature --> select : 特徵向量
select --> tune : 基礎模型
tune --> cv : 最佳參數
cv --> eval : 訓練模型
eval --> deploy : 驗證模型
deploy --> monitor : 生產模型
note right of feature
特徵工程包含:
- 特徵選擇
- 特徵轉換
- 降維處理
end note
note right of eval
評估指標:
- 準確率/召回率
- F1 Score
- AUC-ROC
end note
@enduml
此圖示展示了使用者登入流程的主要步驟。