1. 程式人生 > 其它 >使用flask_sqlalchemy、flask_login、flask_admin模擬最簡單的管理員後臺

使用flask_sqlalchemy、flask_login、flask_admin模擬最簡單的管理員後臺

一、功能描述

使用flask_sqlalchemy、flask_login、flask_admin,模擬管理後臺的登入認證過程。目的是隻讓已經登入的使用者訪問index和admin頁面。

二、功能及效果

1、 訪問index或者後臺admin頁面,自動重定向到首頁

2、登入賬號,如果資料庫裡面檢索到記錄,登入,並重定向到管理頁面。同時,可以訪問index頁面了,也可以讓管理員管理已經註冊到admin的model


3、 使用登出連結之後,重新返回登入頁面

三、完整程式碼

HTML

{% extends 'BASE.html' %}

{% block Content %}
    <h1>lOGIN</h1>
    
    {% for message in get_flashed_messages() %}
        <p>{{ message }}</p>    
    {% endfor %}

    <form action="{{ url_for('login') }}" method="post">
        {% for item in form %}
            <p>{{ item.label }}</p>
            <p>{{ item }}</p>
        {% endfor %}
        <p>
            <input type="submit" value="提交">
        </p>
        <p>
            <a href="{{ url_for('logout') }}">登出</a>
        </p>
    </form>
{% endblock %}

PYTHON

from flask import Flask,render_template,redirect,url_for,request,flash
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin,AdminIndexView,menu
from flask_admin.contrib.sqla import ModelView
from flask_login import LoginManager,UserMixin,login_user,current_user,logout_user,login_required
from flask_wtf import Form
from wtforms import StringField,PasswordField


app = Flask("flask_login_admin")
app.secret_key = "mykey"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///TestDB.sqlite3"

# 使用flask_sqlalchemy,用orm建立使用者資料庫Model,注意一定要繼承UserMixin類
db = SQLAlchemy(app=app)
class Admin_Table(db.Model,UserMixin):
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(20),unique=True)
    password = db.Column(db.String(20))


login_manager = LoginManager(app=app)
# 你必須提供一個 user_loader 回撥。這個回撥用於從會話中儲存的使用者 ID 重新載入使用者物件。它應該接受一個使用者的 unicode ID 作為引數,並且返回相應的使用者物件。
@login_manager.user_loader
def user_log(user_id):
    return Admin_Table.query.get(user_id)

# 使用@login_required裝飾器的時候,如果沒有登入,預設返回錯誤401,如果使用了這個裝飾器,可以設定成重定向到登入頁面
@login_manager.unauthorized_handler
def unauthorized_handler():
    flash("請先登入!")
    return redirect(url_for("login"))


# 使用flask_wtf在前端建立登入表單
class Login_Form(Form):
    username = StringField("使用者名稱")
    password = PasswordField("密碼")

@app.route("/login/",endpoint="login",methods=["GET","POST"])
def login():
    if request.method == "GET":
        # 如果已經登入的話,直接重定向到admin頁面
        if current_user.is_authenticated:
            return redirect(url_for("admin.index"))
        else:
            form = Login_Form()
            return render_template("login.html",form=form)
    elif request.method == "POST":
        form = Login_Form(request.form)
        if form.validate():
            username = form.username.data
            password = form.password.data
            # 檢查資料庫裡面是否有對應的賬密
            user = Admin_Table.query.filter(Admin_Table.username == username,Admin_Table.password == password).first()
            if user:
                # 如果資料庫裡面有記錄,將當前使用者的orm物件新增到flask_login裡面,之後current_user.is_authenticated返回的就是True了
                login_user(user)
                flash("登入成功!")
                return redirect(url_for("admin.index"))
        flash("沒有相關的使用者名稱和密碼!")
        return render_template("login.html",form=form)

# 注意,login_required一下要放在route裝飾器的下面,如果沒有登入,自動使用unauthorized_handler()重定向到login頁面
@app.route("/",endpoint="index")
@login_required
def index():
    return render_template("index.html")

# 用於登出的檢視函式,為了保證只有在登入狀態下才能logout,所以也要加一個@logout_required裝飾器
@app.route("/logout/",endpoint="logout")
@login_required
def logout():
    logout_user()
    flash("登出成功")
    return redirect(url_for("login"))

# 如果只對flask_admin註冊的其中一個檢視函式進行認證,繼承ModelView類,然後改寫裡面的方法就行了,也就是說在沒有認證的前提下,還是可以訪問/admin/路徑,只不過不顯示註冊的檢視函式
class MyModelView(ModelView):
    def is_accessible(self):
        return current_user.is_authenticated
    def inaccessible_callback(self, name, **kwargs):
        return redirect(url_for("login"))

# 對整個admin後臺進行認證,沒有登入認證的話,訪問/admin/就直接重定向到login頁面,和上面的MyModelView類選一個即可實現功能
class MyAdminIndexView(AdminIndexView):
    def is_accessible(self):
        return current_user.is_authenticated
    def inaccessible_callback(self, name, ** kwargs):
        flash("請先登入!")
        return redirect(url_for("login"))

# 在admin頁面的導航添加註銷按鈕
class LogoutMenu(menu.MenuLink):
    def is_accessible(self):
        return current_user.is_authenticated

admin = Admin(app=app,name="Admin測試",endpoint="admin",template_mode="bootstrap4",index_view=MyAdminIndexView())
admin.add_view(MyModelView(Admin_Table,db.session))
admin.add_link(LogoutMenu(name="Logout",endpoint="logout"))


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