今天我會根據這篇 ' Building a Login System with Python Flask and MySQL for Beginners ' 去學習如何利用 FLASK 去製作一個登入系統 ,我主要學習系統製作,所以css等樣式我就直接使用這篇的樣本。
pythonlogin/
├── static/
│ ├── style.css
├── templates/
│ ├── index.html
│ ├── register.html
│ ├── home.html
│ ├── profile.html
│ └── layout.html
└── app.py
首先,在 MySQL Workbench 建立好一個 TABLE (accounts),並新增一份資料以做測試
CREATE DATABASE IF NOT EXISTS `pythonlogin` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `pythonlogin`;
CREATE TABLE IF NOT EXISTS `accounts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(255) NOT NULL,
`email` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO `accounts` (`id`, `username`, `password`, `email`) VALUES (1, 'test', 'test', 'test@test.com');
from flask import Flask, render_template, request, redirect, url_for, session
from flask_mysqldb import MySQL
import MySQLdb.cursors
import MySQLdb.cursors, re, hashlib
app = Flask(__name__)
# 設定這個為您的密鑰(可以是任何東西,用於額外保護)
app.secret_key = 'yoursecretkey'
# 輸入您的資料庫連接詳細信息
app.config['MYSQL_HOST'] = 'localhost'
app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] = 'password'
app.config['MYSQL_DB'] = 'pythonlogin'
# 初始化 MySQL
mysql = MySQL(app)
# 登入頁面 - http://localhost:5000/pythinlogin/
@app.route('/pythonlogin/', methods=['GET', 'POST'])
def login():
# 如果出現問題,輸出一條消息...
msg = ''
# 檢查 POST 請求中是否存在 "username" 和 "password"(用戶提交了表單)
if request.method == 'POST' and 'username' in request.form and 'password' in request.form:
# 創建變量以便於訪問
username = request.form['username']
password = request.form['password']
# 使用 MySQL 檢查帳戶是否存在
cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute('SELECT * FROM accounts WHERE username = %s AND password = %s', (username, password,))
# 獲取一條記錄並返回結果
account = cursor.fetchone()
# 如果帳戶存在於資料庫中的 accounts 表
if account:
# 創建會話數據,我們可以在其他路由中訪問這些數據
session['loggedin'] = True
session['id'] = account['id']
session['username'] = account['username']
# 重定向到主頁
return redirect(url_for('home'))
else:
# 帳戶不存在或用戶名/密碼不正確
msg = '用戶名或密碼不正確!'
# 顯示登錄表單並顯示消息(如果有)
return render_template('index.html', msg=msg)
# 首頁,只能由已登錄的用戶訪問 - http://localhost:5000/pythinlogin/home
@app.route('/pythonlogin/home')
def home():
# 檢查用戶是否已登錄
if 'loggedin' in session:
# 用戶已登錄,顯示主頁
return render_template('home.html', username=session['username'])
# 用戶未登錄,重定向到登錄頁面
return redirect(url_for('login'))
# 登出頁面 - http://localhost:5000/python/logout
@app.route('/pythonlogin/logout')
def logout():
# 移除會話資料,這將使用戶登出
session.pop('loggedin', None)
session.pop('id', None)
session.pop('username', None)
# 重定向到登錄頁面
return redirect(url_for('login'))
# 註冊頁面 - http://localhost:5000/pythinlogin/register
# 需要使用 GET 和 POST 請求
@app.route('/pythonlogin/register', methods=['GET', 'POST'])
def register():
# 如果出現問題,輸出一條消息...
msg = ''
# 檢查 POST 請求中是否存在 "username", "password" 和 "email"(用戶提交了表單)
if request.method == 'POST' and 'username' in request.form and 'password' in request.form and 'email' in request.form:
# 創建變量以便於訪問
username = request.form['username']
password = request.form['password']
email = request.form['email']
# 使用 MySQL 檢查帳戶是否存在
cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute('SELECT * FROM accounts WHERE username = %s', (username))
account = cursor.fetchone()
# 如果帳戶存在,顯示錯誤並進行驗證檢查
if account:
msg = '帳戶已存在!'
elif not re.match(r'[^@]+@[^@]+\.[^@]+', email):
msg = '無效的電子郵件地址!'
elif not re.match(r'[A-Za-z0-9]+', username):
msg = '用戶名只能包含字母和數字!'
elif not username or not password or not email:
msg = '請填寫表單!'
else:
# 帳戶不存在且表單數據有效,現在將新帳戶插入到 accounts 表中
cursor.execute('INSERT INTO accounts VALUES (NULL, %s, %s, %s)', (username, password, email))
mysql.connection.commit()
msg = '您已成功註冊!'
elif request.method == 'POST':
# 表單為空...(沒有 POST 數據)
msg = '請填寫表單!'
# 顯示註冊表單並顯示消息(如果有)
return render_template('register.html', msg=msg)
# 個人資料頁面 - http://localhost:5000/pythinlogin/profile
# 只能由已登錄的用戶訪問
@app.route('/pythonlogin/profile')
def profile():
# 檢查用戶是否已登錄
if 'loggedin' in session:
# 我們需要用戶的所有帳戶信息,以便在個人資料頁面上顯示
cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute('SELECT * FROM accounts WHERE id = %s', [session['id']])
account = cursor.fetchone()
# 顯示帶有帳戶信息的個人資料頁面
return render_template('profile.html', account=account)
# 用戶未登錄,重定向到登錄頁面
return redirect(url_for('login'))
if __name__ == "__main__":
app.run(debug=True)
建立了包含輸入欄位的表單:使用者名稱和密碼,表單的方法設定為post,這將使用 POST 請求將表單資料傳送到我們的 Python Flask 伺服器
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Login</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
</head>
<body>
<div class="login">
<h1>Login</h1>
<div class="links">
<a href="{{ url_for('login') }}" class="active">Login</a>
<a href="{{ url_for('register') }}">Register</a>
</div>
<form action="{{ url_for('login') }}" method="post">
<label for="username">
<i class="fas fa-user"></i>
</label>
<input type="text" name="username" placeholder="Username" id="username" required>
<label for="password">
<i class="fas fa-lock"></i>
</label>
<input type="password" name="password" placeholder="Password" id="password" required>
<div class="msg">{{ msg }}</div>
<input type="submit" value="Login">
</form>
</div>
</body>
</html>
表單的action屬性設定為「register」路由,我們將使用該路由來處理POST請求
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Register</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
</head>
<body>
<div class="register">
<h1>Register</h1>
<div class="links">
<a href="{{ url_for('login') }}">Login</a>
<a href="{{ url_for('register') }}" class="active">Register</a>
</div>
<form action="{{ url_for('register') }}" method="post" autocomplete="off">
<label for="username">
<i class="fas fa-user"></i>
</label>
<input type="text" name="username" placeholder="Username" id="username" required>
<label for="password">
<i class="fas fa-lock"></i>
</label>
<input type="password" name="password" placeholder="Password" id="password" required>
<label for="email">
<i class="fas fa-envelope"></i>
</label>
<input type="email" name="email" placeholder="Email" id="email" required>
<div class="msg">{{ msg }}</div>
<input type="submit" value="Register">
</form>
</div>
</body>
</html>
在主頁(home.html)和個人資料(profile.html)頁面上使用相同的佈局
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
</head>
<body class="loggedin">
<nav class="navtop">
<div>
<h1>Website Title</h1>
<a href="{{ url_for('home') }}"><i class="fas fa-home"></i>Home</a>
<a href="{{ url_for('profile') }}"><i class="fas fa-user-circle"></i>Profile</a>
<a href="{{ url_for('logout') }}"><i class="fas fa-sign-out-alt"></i>Logout</a>
</div>
</nav>
<div class="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
使用者登入後的主頁
{% extends 'layout.html' %}
{% block title %}Home{% endblock %}
{% block content %}
<h2>Home Page</h2>
<p>Welcome back, {{ username }}!</p>
{% endblock %}
使用者可以在個人資料頁面查看其詳細資訊(使用者名稱、密碼和電子郵件)
{% extends 'layout.html' %}
{% block title %}Profile{% endblock %}
{% block content %}
<h2>Profile Page</h2>
<div>
<p>Your account details are below:</p>
<table>
<tr>
<td>Username:</td>
<td>{{ account['username'] }}</td>
</tr>
<tr>
<td>Password:</td>
<td>{{ account['password'] }}</td>
</tr>
<tr>
<td>Email:</td>
<td>{{ account['email'] }}</td>
</tr>
</table>
</div>
{% endblock %}
參考資料 :
https://morioh.com/a/c61187faa9be/building-a-login-system-with-python-flask-and-mysql-for-beginners
Python Flask Authentication Tutorial - Learn Flask Login