1.登录验证初始化
from flask import Flask, session, g
from flask_login import LoginManager
from models import db, User
from accounts.views import accounts
from qa.views import qa
from utils.filters import number_split
app = Flask(__name__, static_folder='assets')
# 从配置文件加载配置
app.config.from_object('conf.Config')
# 数据库初始化
db.init_app(app)
# 登录验证初始化
login_manager = LoginManager()
login_manager.login_view = "accounts.login"
login_manager.login_message = '请登录'
login_manager.login_message_category = "danger"
login_manager.init_app(app)
# 注册蓝图
app.register_blueprint(accounts, url_prefix='/accounts')
app.register_blueprint(qa, url_prefix='/')
# 注册过滤器
app.jinja_env.filters['number_split'] = number_split
#
# @app.before_request
# def before_request():
# """ 如果有用户id,设置到全局对象 """
# user_id = session.get('user_id', None)
# if user_id:
# user = User.query.get(user_id)
# print(user)
# g.current_user = user
#实现登录验证,操作必须登录才可以
@login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
2.视图函数中添加
@login_required
from flask import Blueprint, render_template, request, abort
from flask_login import login_required
from models import Question
qa = Blueprint("qa", __name__, template_folder="templates", static_folder="../assets")
@qa.route('/')
def index():
""" 首页 """
return render_template('index.html')
@qa.route('/follow')
def follow():
""" 关注 """
# 每页数据的大小
per_page = 20
page = int(request.args.get('page', 1))
page_date = Question.query.filter_by(is_valid=True).paginate(page=page, per_page=per_page)
return render_template('follow.html', page_date=page_date)
@qa.route('/write')
@login_required
def write():
""" 写文章,提问 """
return render_template('write.html')
@qa.route('/detail/<int:q_id>')
def detail(q_id):
""" 问题详情 """
# 查询问题信息
question = Question.query.get(q_id)
# 当文章被删除,返回404
if not question.is_valid:
abort(404)
# 2.展示第一条回答信息
answer = question.answer_list.filter_by(is_valid=True).first()
return render_template('detail.html', question=question, answer=answer)
3.在对应的表单中或视图函数中调用
flask_login提供的login_user方法传入user对象
import hashlib
from flask import request
from flask_login import login_user
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, ValidationError
from wtforms.validators import DataRequired, Length, EqualTo
from models import User, db, UserProfile, UserLoginHistory
from utils import constans
from utils.validators import phone_required
class RegisterForm(FlaskForm):
"""用户注册"""
# render_kw添加其余属性,如bootstarp中的class属性或样式,或默认值
username = StringField(label='用户名', render_kw={
'class': 'form-control input-lg',
'placeholder': '请输入用户名'
}, validators=[DataRequired('请输入用户名'), phone_required])
nickname = StringField(label='昵称', render_kw={
'class': 'form-control input-lg',
'placeholder': '请输入昵称'
}, validators=[DataRequired('请输入昵称'), Length(min=2, max=20, message='昵称长度在2~20之间')])
password = PasswordField(label='密码', render_kw={
'class': 'form-control input-lg',
'placeholder': '请输入密码'
}, validators=[DataRequired('请输入密码')])
confirm_password = PasswordField(label='确认密码', render_kw={
'class': 'form-control input-lg',
'placeholder': '请确认密码'
}, validators=[DataRequired('请输入确认密码'), EqualTo('password', message='二次密码输入不一致')])
def validate_username(self, field):
"""检测用户名是否已经存在"""
user = User.query.filter_by(username=field.data).first()
if user:
raise ValidationError("用户名已存在")
return field
def register(self):
"""用户注册方法"""
# 1.获取表单数据
username = self.username.data
nickname = self.nickname.data
password = self.password.data
# 2.构建用户对象
try:
# 将密码加密存储
password = hashlib.sha256(password.encode()).hexdigest()
user_obj = User(
username=username,
nickname=nickname,
password=password
)
db.session.add(user_obj)
profile = UserProfile(username=username, user=user_obj)
db.session.add(profile)
# 3.提交到数据库
db.session.commit()
return user_obj
except Exception as e:
print(e)
return None
class loginForm(FlaskForm):
"""用户登录"""
# render_kw添加其余属性,如bootstarp中的class属性或样式,或默认值
username = StringField(label='用户名', render_kw={
'class': 'form-control input-lg',
'placeholder': '请输入用户名'
}, validators=[DataRequired('请输入用户名'), phone_required])
password = PasswordField(label='密码', render_kw={
'class': 'form-control input-lg',
'placeholder': '请输入密码'
}, validators=[DataRequired('请输入密码')])
def validate(self):
print('自动执行???')
result = super().validate()
username = self.username.data
password = self.password.data
if result:
# TODO 验证加密后的密码是否正确
user = User.query.filter_by(username=username, password=password).first()
if user is None:
result = False
# 未验证通过,给username一个指定的错误信息
self.username.errors = ['用户名或密码错误']
elif user.status == constans.UserStatus.USER_IN_ACTIVE.value:
result = False
# 未验证通过,给username一个指定的错误信息
self.username.errors = ['用户已被禁用']
return result
def do_login(self):
try:
username = self.username.data
password = self.password.data
# 1.查找用户
# TODO 验证加密后的密码是否正确
user = User.query.filter_by(username=username, password=password).first()
# 2.登录用户
# session['user_id'] = user.id
# 3.调用login_user
login_user(user)
ip = request.remote_addr
ua = request.headers.get('user-agent', None)
obj = UserLoginHistory(username=username, ip=ip, ua=ua, user=user)
db.session.add(obj)
db.session.commit()
return user
except Exception as e:
print(e)
return None
4.退出参考官网
当用户准备退出时:
直接调用login_user()他们将被注销,并且他们会话的所有 cookie 都将被清除。