使用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)

浙公网安备 33010602011771号