Flask Session 登錄認證模塊

来源:https://www.cnblogs.com/LyShark/archive/2023/11/27/17858903.html
-Advertisement-
Play Games

Flask 框架提供了強大的 Session 模塊組件,為 Web 應用實現用戶註冊與登錄系統提供了方便的機制。結合 Flask-WTF 表單組件,我們能夠輕鬆地設計出用戶友好且具備美觀界面的註冊和登錄頁面,使這一功能能夠直接應用到我們的項目中。本文將深入探討如何通過 Flask 和 Flask-W... ...


Flask 框架提供了強大的 Session 模塊組件,為 Web 應用實現用戶註冊與登錄系統提供了方便的機制。結合 Flask-WTF 表單組件,我們能夠輕鬆地設計出用戶友好且具備美觀界面的註冊和登錄頁面,使這一功能能夠直接應用到我們的項目中。本文將深入探討如何通過 Flask 和 Flask-WTF 構建一個完整的用戶註冊與登錄系統,以及如何對頁面進行優化美化,提高用戶體驗。通過這一系統,用戶能夠方便註冊賬戶、安全登錄,並且我們能夠有效管理用戶的會話信息,為 Web 應用的用戶管理提供一種高效的解決方案。

什麼是Session機制?

Session 是一種在 Web 應用中用於存儲用戶特定信息的機制。它允許在用戶訪問網站時存儲和檢索信息,以便在用戶的不同請求之間保持狀態。Session 機制在用戶登錄、購物網站、個性化設置等場景中得到廣泛應用,它為用戶提供了更加連貫和個性化的體驗。在 Flask 中,通過 Flask Session 模塊可以方便地使用 Session ,實現用戶狀態的維護和管理。

在 Web 開發中,HTTP 協議是無狀態的,即每個請求都是獨立的,伺服器不會記住之前的請求信息。為瞭解決這個問題,引入了 Session 機制。基本思想是在用戶訪問網站時,伺服器生成一個唯一的 Session ID,並將這個 ID 存儲在用戶的瀏覽器中(通常通過 Cookie)。同時,伺服器端會保存一個映射,將 Session ID 與用戶的相關信息關聯起來,這樣在用戶的後續請求中,伺服器就能根據 Session ID 找到相應的用戶信息,從而實現狀態的保持。

Session 的認證流程通常包括以下步驟:

  1. 用戶登錄: 用戶通過提供用戶名和密碼進行登錄。在登錄驗證成功後,伺服器為該用戶創建一個唯一的 Session ID,並將這個 ID 存儲在用戶瀏覽器的 Cookie 中。
  2. Session 存儲: 伺服器端將用戶的相關信息(如用戶 ID、許可權等)與 Session ID 關聯起來,並將這些信息存儲在伺服器端的 Session 存儲中。Session 存儲可以是記憶體、資料庫或其他持久化存儲方式。
  3. Session ID 傳遞: 伺服器將生成的 Session ID 發送給用戶瀏覽器,通常是通過 Set-Cookie 頭部。這個 Cookie 會在用戶的每次請求中被包含在 HTTP 頭中。
  4. 後續請求: 用戶在後續的請求中會攜帶包含 Session ID 的 Cookie。伺服器通過解析請求中的 Session ID,從 Session 存儲中檢索用戶的信息,以恢復用戶的狀態。
  5. 認證檢查: 伺服器在每次請求中檢查 Session ID 的有效性,並驗證用戶的身份。如果 Session ID 無效或過期,用戶可能需要重新登錄。
  6. 用戶登出: 當用戶主動註銷或 Session 過期時,伺服器將刪除與 Session ID 關聯的用戶信息,用戶需要重新登錄。

總體而言,Session 的認證流程通過在客戶端和伺服器端之間傳遞唯一的 Session ID,實現了用戶狀態的持久化和管理。這種機制使得用戶可以在多個請求之間保持登錄狀態,提供了一種有效的用戶認證方式。在 Flask 中,開發者可以方便地使用 Flask 提供的 Session 模塊來實現這一流程。

Session 認證基礎

預設情況下,直接使用Session模塊即可實現Session登錄會話保持,該方式是將Session存儲到記憶體中,程式重啟後即釋放,Session的設置一般可以通過使用session["username"]賦值的方式進行,如需驗證該Session的可靠性,則只需要調用session.get方法即可一得到特定欄位,通過對欄位的判斷即可實現認證機制。

如下是一個Flask後端代碼,運行後通過訪問http://127.0.0.1:5000進入到登錄這頁面。

from flask import Flask,session,render_template,request,Response,redirect,url_for
from functools import wraps
import os

app = Flask(__name__, static_folder="./template",template_folder="./template")
app.config['SECRET_KEY'] = os.urandom(24)

# 登錄認證裝飾器
def login_required(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if session.get("username") != None and session.get("is_login") ==True:
            print("登陸過則繼續執行原函數")
            return func(*args, **kwargs)
        else:
            print("沒有登錄則跳轉到登錄頁面")
            resp = Response()
            resp.status_code=200
            resp.data = "<script>window.location.href='/login';</script>"
            return resp
    return wrapper

@app.route("/login",methods=["GET","POST"])
def login():
    if request.method == "GET":
        html = """
                <form action="/login" method="post">
                    <p>賬號: <input type="text" name="username"></p>
                    <p>密碼: <input type="password" name="password"></p>
                    <input type="submit" value="登錄">
                </form>
                """
        return html

    if request.method == "POST":
        get_dict = request.form.to_dict()

        get_username = get_dict['username']
        get_password = get_dict['password']

        if (get_username == "lyshark" or get_username == "admin") and get_password == "123123":
            session["username"] = get_username
            session["is_login"] = True

            print("登錄完成直接跳到主頁")
            resp = Response()
            resp.status_code=200
            resp.data = "<script>window.location.href='/index';</script>"
            return resp
        else:
            return "登陸失敗"
    return "未知錯誤"

# 主頁菜單
@app.route("/index",methods = ["GET","POST"])
@login_required
def index():
    username = session.get("username")
    return "用戶 {} 您好,這是主頁面".format(username)

# 第二個菜單
@app.route("/get",methods = ["GET","POST"])
@login_required
def get():
    username = session.get("username")
    return "用戶 {} 您好,這是子頁面".format(username)

@app.route("/logout",methods = ["GET","POST"])
@login_required
def logout():
    username = session.get("username")

    # 登出操作
    session.pop("username")
    session.pop("is_login")
    session.clear()
    return "用戶 {} 已註銷".format(username)

if __name__ == '__main__':
    app.run()

程式運行後,當用戶訪問http://127.0.0.1:5000地址則會跳轉到login登陸頁面,此時如果用戶第一次訪問則會輸出如下所示的登陸信息;

通過輸入正確的用戶名lyshark和密碼123123則可以登錄成功,此處登錄的用戶是lyshark如下圖。

通過輸入不同的用戶登錄會出現不同的頁面提示信息,如下圖則是admin的主頁信息。

當我們手動輸入logout時則此時會退出登錄用戶,後臺也會清除該用戶的Session,在開發中可以自動跳轉到登出頁面;

Session 使用資料庫

通過結合 Session 與 SQLite 資料庫,我們可以實現一個更完善的用戶註冊、登錄以及密碼修改功能。在這個案例中,首先,用戶可以通過註冊表單輸入用戶名、密碼等信息,這些信息經過驗證後將被存儲到 SQLite 資料庫中。註冊成功後,用戶可以使用相同的用戶名和密碼進行登錄。登錄成功後,我們使用 Flask 的 Session 機制將用戶信息保存在伺服器端,確保用戶在訪問其他頁面時仍然處於登錄狀態。

為了增加更多功能,我們還可以實現密碼修改的功能。用戶在登錄狀態下,通過密碼修改表單輸入新的密碼,我們將新密碼更新到資料庫中,確保用戶可以安全地更改密碼。這個案例綜合運用了 Flask、SQLite 和 Session 等功能,為 Web 應用提供了一套完整的用戶管理系統。

from flask import Flask,request,render_template,session,Response
import sqlite3,os
from functools import wraps

app = Flask(__name__)

app.config['SECRET_KEY'] = os.urandom(24)

# 創建資料庫
def UserDB():
    conn = sqlite3.connect("./database.db")
    cursor = conn.cursor()
    create = "create table UserDB(" \
             "uid INTEGER primary key AUTOINCREMENT not null unique," \
             "username char(64) not null unique," \
             "password char(64) not null," \
             "email char(64) not null" \
             ")"
    cursor.execute(create)
    conn.commit()
    cursor.close()
    conn.close()

# 增刪改查簡單封裝
def RunSqlite(db,table,action,field,value):
    connect = sqlite3.connect(db)
    cursor = connect.cursor()

    # 執行插入動作
    if action == "insert":
        insert = f"insert into {table}({field}) values({value});"
        if insert == None or len(insert) == 0:
            return False
        try:
            cursor.execute(insert)
        except Exception:
            return False

    # 執行更新操作
    elif action == "update":
        update = f"update {table} set {value} where {field};"
        if update == None or len(update) == 0:
            return False
        try:
            cursor.execute(update)
        except Exception:
            return False

    # 執行查詢操作
    elif action == "select":

        # 查詢條件是否為空
        if value == "none":
            select = f"select {field} from {table};"
        else:
            select = f"select {field} from {table} where {value};"

        try:
            ref = cursor.execute(select)
            ref_data = ref.fetchall()
            connect.commit()
            connect.close()
            return ref_data
        except Exception:
            return False

    # 執行刪除操作
    elif action == "delete":
        delete = f"delete from {table} where {field};"
        if delete == None or len(delete) == 0:
            return False
        try:
            cursor.execute(delete)
        except Exception:
            return False
    try:
        connect.commit()
        connect.close()
        return True
    except Exception:
        return False

# 創建資料庫
@app.route("/create")
def create():
    UserDB()
    return "create success"

# 登錄認證裝飾器
def login_required(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if session.get("username") != None and session.get("is_login") ==True:
            print("登陸過則繼續執行原函數")
            return func(*args, **kwargs)
        else:
            print("沒有登錄則跳轉到登錄頁面")
            resp = Response()
            resp.status_code=200
            resp.data = "<script>window.location.href='/login';</script>"
            return resp
    return wrapper

# 用戶註冊頁面
@app.route("/register",methods=["GET","POST"])
def register():
    if request.method == "GET":
        html = """
                <form action="/register" method="post">
                    <p>賬號: <input type="text" name="username"></p>
                    <p>密碼: <input type="password" name="password"></p>
                    <p>郵箱: <input type="text", name="email"></p>
                    <input type="submit" value="用戶註冊">
                </form>
                """
        return html

    if request.method == "POST":
        username = request.form.get("username")
        password = request.form.get("password")
        email = request.form.get("email")

        if RunSqlite("database.db","UserDB","select","username",f"username='{username}'") == []:
            insert = RunSqlite("database.db","UserDB","insert","username,password,email",f"'{username}','{password}','{email}'")
            if insert == True:
                return "創建完成"
            else:
                return "創建失敗"
        else:
            return "用戶存在"
        return "未知錯誤"

# 用戶登錄模塊
@app.route("/login",methods=["GET","POST"])
def login():
    if request.method == "GET":
        html = """
                <form action="/login" method="post">
                    <p>賬號: <input type="text" name="username"></p>
                    <p>密碼: <input type="password" name="password"></p>
                    <input type="submit" value="登錄">
                </form>
                """
        return html

    if request.method == "POST":
        username = request.form.get("username")
        password = request.form.get("password")

        select = RunSqlite("database.db","UserDB","select","username,password",f"username='{username}'")
        if select != []:
            # 繼續驗證密碼
            if select[0][1] == password:
                session["username"] = username
                session["is_login"] = True

                print("登錄完成直接跳到主頁")
                resp = Response()
                resp.status_code = 200
                resp.data = "<script>window.location.href='/index';</script>"
                return resp
            else:
                return "密碼不正確"
        else:
            return "用戶不存在"
    return "未知錯誤"

# 修改密碼
@app.route("/modify",methods=["GET","POST"])
@login_required
def modify():
    if request.method == "GET":
        html = """
                <form action="/modify" method="post">
                    <p>新密碼: <input type="password" name="new_password"></p>
                    <input type="submit" value="修改密碼">
                </form>
                """
        return html

    if request.method == "POST":
        username = session.get("username")
        new_password = request.form.get("new_password")
        update = RunSqlite("database.db","UserDB","update",f"username='{username}'",f"password='{new_password}'")
        if update == True:
            # 登出操作
            session.pop("username")
            session.pop("is_login")
            session.clear()

            print("密碼已更新,請重新登錄")
            resp = Response()
            resp.status_code = 200
            resp.data = "<script>window.location.href='/login';</script>"
            return resp
        else:
            return "密碼更新失敗"
    return "未知錯誤"

# 主頁菜單
@app.route("/index",methods = ["GET","POST"])
@login_required
def index():
    username = session.get("username")
    return "用戶 {} 您好,這是主頁面".format(username)

# 第二個菜單
@app.route("/get",methods = ["GET","POST"])
@login_required
def get():
    username = session.get("username")
    return "用戶 {} 您好,這是子頁面".format(username)

@app.route("/logout",methods = ["GET","POST"])
@login_required
def logout():
    username = session.get("username")

    # 登出操作
    session.pop("username")
    session.pop("is_login")
    session.clear()
    return "用戶 {} 已註銷".format(username)

if __name__ == '__main__':
    app.run(debug=True)

案例被運行後首先通過調用http://127.0.0.1:5000/create創建database.db資料庫,接著我們可以通過訪問/register路徑實現賬號註冊功能,如下我們註冊lyshark密碼是123123,輸出效果如下所示;

通過訪問/modify可實現對用戶密碼的修改,但在修改之前需要先通過/login頁面登錄後進行,否則會預設跳轉到用戶登錄頁面中;

使用WTForms登錄模板

在如上代碼基礎上,我們著重增加一個美化登錄模板,以提升用戶在註冊登錄流程中的整體體驗。通過引入WTF表單組件和Flask-WTF擴展,在前端實現了一個更友好的登錄頁面。

此登錄模板的設計考慮了頁面佈局、顏色搭配、表單樣式等因素,以確保用戶在輸入用戶名和密碼時感到輕鬆自然。同時,我們利用Flask-WTF的驗證器功能,對用戶輸入的數據進行有效性檢查,保障了用戶信息的安全性。

首先,我們需要在template目錄下,創建register.html前端文件,用於用戶註冊,並寫入以下代碼。

<html>
<head>
    <link rel="stylesheet" href="https://www.lyshark.com/javascript/bootstrap/3.3.7/css/bootstrap.min.css">
    <link href="https://www.lyshark.com/javascript/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
    <link href="https://www.lyshark.com/javascript/other/my_login.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-offset-3 col-md-6">
                <form action="/register" method="post" class="form-horizontal">
                    {{ form.csrf_token }}

                    <span class="heading">用 戶 註 冊</span>
                    <div class="form-group">
                        {{ form.username }}
                        <i class="fa fa-user"></i>
                        <a href="/login" class="fa fa-question-circle"></a>
                    </div>
                    <div class="form-group">
                        {{ form.email }}
                        <i class="fa fa-envelope"></i>
                    </div>
                    <div class="form-group">
                        {{ form.password }}
                        <i class="fa fa-lock"></i>
                    </div>
                    <div class="form-group">
                        {{ form.RepeatPassword }}
                        <i class="fa fa-unlock-alt"></i>
                    </div>
                    {{ form.submit }}
                </form>
            </div>
        </div>
    </div>
</body>
</html>

接著,繼續創建login.html前端文件,用於登錄賬號時使用,並寫入以下代碼。

<html>
<head>
    <link rel="stylesheet" href="https://www.lyshark.com/javascript/bootstrap/3.3.7/css/bootstrap.min.css">
    <link href="https://www.lyshark.com/javascript/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
    <link href="https://www.lyshark.com/javascript/other/my_login.css" rel="stylesheet" type="text/css" />
</head>
    <body>
        <div class="container">
            <div class="row">
                <div class="col-md-offset-3 col-md-6">
                    <form action="/login" method="post" class="form-horizontal">
                        {{ form.csrf_token }}

                        <span class="heading">用 戶 登 錄</span>
                        <div class="form-group">
                            {{ form.username }}
                            <i class="fa fa-user"></i>
                        </div>
                        <div class="form-group help">
                            {{ form.password }}
                            <i class="fa fa-lock"></i>
                            <a href="#" class="fa fa-question-circle"></a>
                        </div>
                        <div class="form-group">
                            <button type="submit" class="btn btn-success">登 錄 後 台</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </body>
</html>

後臺代碼部分,我們需要在原代碼的基礎之上,增加對前端註冊和登錄頁面的渲染類,此處使用flask_wtf組件實現渲染生成,具體代碼如下。

from flask import Flask,request,render_template,session,Response
from functools import wraps
import sqlite3,os

from flask_wtf import FlaskForm
from wtforms import widgets,validators
from wtforms.validators import DataRequired,Regexp,DataRequired, Length, Email, EqualTo, NumberRange
from wtforms.fields import (StringField, PasswordField, DateField, BooleanField,DateTimeField,TimeField,
                            SelectField, SelectMultipleField, TextAreaField,FloatField,HiddenField,
                            RadioField, IntegerField, DecimalField, SubmitField, IntegerRangeField)

# app = Flask(__name__, static_folder="./template",template_folder="./template")
app = Flask(__name__)

app.config["SECRET_KEY"] = "d3d3Lmx5c2hhcmsuY29t"

# -----------------------------------------------------------------------------
# 創建資料庫
def UserDB():
    conn = sqlite3.connect("database.db")
    cursor = conn.cursor()
    create = "create table UserDB(" \
             "uid INTEGER primary key AUTOINCREMENT not null unique," \
             "username char(64) not null unique," \
             "password char(64) not null," \
             "email char(64) not null" \
             ")"
    cursor.execute(create)
    conn.commit()
    cursor.close()
    conn.close()

# 增刪改查簡單封裝
def RunSqlite(db,table,action,field,value):
    connect = sqlite3.connect(db)
    cursor = connect.cursor()

    # 執行插入動作
    if action == "insert":
        insert = f"insert into {table}({field}) values({value});"
        if insert == None or len(insert) == 0:
            return False
        try:
            cursor.execute(insert)
        except Exception:
            return False

    # 執行更新操作
    elif action == "update":
        update = f"update {table} set {value} where {field};"
        if update == None or len(update) == 0:
            return False
        try:
            cursor.execute(update)
        except Exception:
            return False

    # 執行查詢操作
    elif action == "select":

        # 查詢條件是否為空
        if value == "none":
            select = f"select {field} from {table};"
        else:
            select = f"select {field} from {table} where {value};"

        try:
            ref = cursor.execute(select)
            ref_data = ref.fetchall()
            connect.commit()
            connect.close()
            return ref_data
        except Exception:
            return False

    # 執行刪除操作
    elif action == "delete":
        delete = f"delete from {table} where {field};"
        if delete == None or len(delete) == 0:
            return False
        try:
            cursor.execute(delete)
        except Exception:
            return False
    try:
        connect.commit()
        connect.close()
        return True
    except Exception:
        return False

# -----------------------------------------------------------------------------
# 生成用戶註冊表單
class RegisterForm(FlaskForm):
    username = StringField(
        validators=[
            DataRequired(message='用戶名不能為空'),
            Length(min=1, max=15, message='用戶名長度必須大於%(min)d且小於%(max)d')
        ],
        widget=widgets.TextInput(),
        render_kw={'class': 'form-control', "placeholder":"輸入註冊用戶名"}
    )
    email = StringField(
        validators=[validators.DataRequired(message='郵箱不能為空'),validators.Email(message="郵箱格式輸入有誤")],
        render_kw={'class':'form-control', "placeholder":"輸入Email郵箱"}
    )
    password = PasswordField(
        validators=[
            validators.DataRequired(message='密碼不能為空'),
            validators.Length(min=5, message='用戶名長度必須大於%(min)d'),
            validators.Regexp(regex="[0-9a-zA-Z]{5,}",message='密碼不允許使用特殊字元')
        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control', "placeholder":"輸入用戶密碼"}
    )
    RepeatPassword = PasswordField(
        validators=[
            validators.DataRequired(message='密碼不能為空'),
            validators.Length(min=5, message='密碼長度必須大於%(min)d'),
            validators.Regexp(regex="[0-9a-zA-Z]{5,}",message='密碼不允許使用特殊字元'),
            validators.EqualTo("password",message="兩次密碼輸入必須一致")
        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control', "placeholder":"再次輸入密碼"}
    )
    submit = SubmitField(
        label="用 戶 註 冊", render_kw={ "class":"btn btn-success" }
    )

# 生成用戶登錄表單
class LoginForm(FlaskForm):
    username = StringField(
        validators=[
            validators.DataRequired(message=''),
            validators.Length(min=4, max=15, message=''),
            validators.Regexp(regex="[0-9a-zA-Z]{4,15}", message='')
        ],
        widget=widgets.TextInput(),
        render_kw={"class":"form-control", "placeholder":"請輸入用戶名或電子郵件"}
    )
    password = PasswordField(
        validators=[
            validators.DataRequired(message=''),
            validators.Length(min=5, max=15,message=''),
            validators.Regexp(regex="[0-9a-zA-Z]{5,15}",message='')
        ],
        widget=widgets.PasswordInput(),
        render_kw={"class":"form-control", "placeholder":"請輸入密碼"}
    )

# -----------------------------------------------------------------------------
# 創建資料庫
@app.route("/create")
def create():
    UserDB()
    return "create success"

# 登錄認證裝飾器
def login_required(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if session.get("username") != None and session.get("is_login") ==True:
            print("登陸過則繼續執行原函數")
            return func(*args, **kwargs)
        else:
            print("沒有登錄則跳轉到登錄頁面")
            resp = Response()
            resp.status_code=200
            resp.data = "<script>window.location.href='/login';</script>"
            return resp
    return wrapper

# 用戶註冊頁面
@app.route("/register",methods=["GET","POST"])
def register():
    form = RegisterForm(csrf_enabled = True)

    if request.method == "POST":
        if form.validate_on_submit():
            username = form.username.data
            password = form.RepeatPassword.data
            email = form.email.data
            print("用戶: {} 郵箱: {}".format(username,email))

            if RunSqlite("database.db", "UserDB", "select", "username", f"username='{username}'") == []:
                insert = RunSqlite("database.db", "UserDB", "insert", "username,password,email",
                                   f"'{username}','{password}','{email}'")
                if insert == True:
                    return "創建完成"
                else:
                    return "創建失敗"
            else:
                return "用戶存在"

    return render_template("register.html", form=form)

# 用戶登錄頁面
@app.route("/login",methods=["GET","POST"])
def login():
    form = LoginForm(csrf_enabled = True)

    if request.method == "POST":
        username = form.username.data
        password = form.password.data

        select = RunSqlite("database.db","UserDB","select","username,password",f"username='{username}'")
        if select != []:
            # 繼續驗證密碼
            if select[0][1] == password:
                session["username"] = username
                session["is_login"] = True

                print("登錄完成直接跳到主頁")
                resp = Response()
                resp.status_code = 200
                resp.data = "<script>window.location.href='/index';</script>"
                return resp
            else:
                return "密碼不正確"
        else:
            return "用戶不存在"

    return render_template("login.html", form=form)

# 修改密碼
@app.route("/modify",methods=["GET","POST"])
@login_required
def modify():
    if request.method == "GET":
        html = """
                <form action="/modify" method="post">
                    <p>新密碼: <input type="password" name="new_password"></p>
                    <input type="submit" value="修改密碼">
                </form>
                """
        return html

    if request.method == "POST":
        username = session.get("username")
        new_password = request.form.get("new_password")
        update = RunSqlite("database.db","UserDB","update",f"username='{username}'",f"password='{new_password}'")
        if update == True:
            # 登出操作
            session.pop("username")
            session.pop("is_login")
            session.clear()

            print("密碼已更新,請重新登錄")
            resp = Response()
            resp.status_code = 200
            resp.data = "<script>window.location.href='/login';</script>"
            return resp
        else:
            return "密碼更新失敗"
    return "未知錯誤"

# 主頁菜單
@app.route("/index",methods = ["GET","POST"])
@login_required
def index():
    username = session.get("username")
    return "用戶 {} 您好,這是主頁面".format(username)

# 第二個菜單
@app.route("/get",methods = ["GET","POST"])
@login_required
def get():
    username = session.get("username")
    return "用戶 {} 您好,這是子頁面".format(username)

@app.route("/logout",methods = ["GET","POST"])
@login_required
def logout():
    username = session.get("username")

    # 登出操作
    session.pop("username")
    session.pop("is_login")
    session.clear()
    return "用戶 {} 已註銷".format(username)

if __name__ == '__main__':
    app.run(debug=True)

目錄結果如下圖所示;

當用戶訪問/register時,則可以看到通過flask_wtf渲染後的用戶註冊頁面,如下圖所示;

用戶訪問/login時,則是用戶登錄頁面,如下圖所示;

文章出處:https://www.cnblogs.com/LyShark/p/17858903.html
本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • keycloak可以幫助我們實現這個功能:用戶token每5分鐘失效一次,失效後通過refresh_token來換新的token,而refresh_token每30天失效一次,但如果用戶3天都沒有任何操作(就是沒有用refresh_token去換新的token),那麼3天後也讓refresh_tok ...
  • 1 簡介 Spring Data Redis是 Spring Data 系列的一部分,它提供了Spring應用程式對Redis的輕鬆配置和使用。它不僅提供了對Redis操作的高級抽象,還支持Jedis和Lettuce兩種連接方式。 可通過簡單的配置就能連接Redis,並且可以切換Jedis和Lett ...
  • PlayImage 記得一鍵三連哦 一個使用簡單的QPainter繪圖事件實現圖片播放器的簡易demo 支持圖片切換 支持多路更新,自己擴展即可 支持幻燈片播放 PlayImage自定義控制項支持復用,對外提供updateImage和updatePixmap介面,對傳入的image和pixmap進行圖 ...
  • Flask前後端數據動態交互涉及用戶界面與伺服器之間的靈活數據傳遞。用戶界面使用ECharts圖形庫實時渲染數據。它提供了豐富多彩、交互性強的圖表和地圖,能夠在網頁上直觀、生動地展示數據。ECharts支持各種常見的圖表類型,包括折線圖、柱狀圖、餅圖、散點圖等,同時還支持動畫效果、數據篩選、區域縮放... ...
  • Redis以其速度而聞名。 1 業務數據緩存 1.1 通用數據緩存 string,int,list,map。Redis 最常見的用例是緩存對象以加速 Web 應用程式。 此用例中,Redis 將頻繁請求的數據存儲在記憶體。允許 Web 伺服器快速返回頻繁訪問的數據。這減輕資料庫的負載並提高應用程式RT ...
  • 在Flask框架中,實現Token認證機制並不是一件複雜的事情。除了使用官方提供的`flask_httpauth`模塊或者第三方模塊`flask-jwt`,我們還可以考慮自己實現一個簡易版的Token認證工具。自定義Token認證機制的本質是生成一個令牌(Token),併在用戶每次請求時驗證這個令牌... ...
  • 公眾號「架構成長指南」,專註於生產實踐、雲原生、分散式系統、大數據技術分享。 目的 Spring Cloud 線上微服務實例都是2個起步,如果出問題後,在沒有ELK等日誌分析平臺,如何確定調用到了目標服務的那個實例,以此來排查問題 效果 可以看到服務有幾個實例是上線,並且最終調用了那個實例 考慮到S ...
  • 原文: https://openaigptguide.com/what-is-openai/ OpenAI 是一家人工智慧研究公司,成立於2015年,總部位於美國舊金山。目前,OpenAI由創始人Sam Altman、首席技術官Ilya Sutskever、首席執行官Ilya Sutskever(同 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...