#用户管理
用户注册激活
-
在基础模板base.html中,导航条上添加注册的点击链接,如下:
<li><a href="{{ url_for('user.register') }}">注册</a></li>
因为我们的视图函数是写在蓝本中的,因此反向构造路由时需要指定蓝本,
若不指定蓝本(就是视图前面只有一个.),默认表示当前的蓝本。
-
添加用户注册的视图函数,如下:
@user.route('/register/') def register(): return render_template('user/register.html')
-
创建用户注册的模板文件,如下:
{% extends 'common/base.html' %} {% block title %}用户注册{% endblock %} {% block page_content %} 欢迎注册 {% endblock %}
-
添加用户注册的表单,如下:
from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import DataRequired, Length, EqualTo, Email # 用户注册表单 class RegisterForm(FlaskForm): username = StringField('用户名', validators=[DataRequired(), Length(4, 20, message='用户名只能在4~20个字符之间')]) password = PasswordField('密码', validators=[DataRequired(), Length(6, 20, message='密码长度必须在6~20个字符之间')]) confirm = PasswordField('确认密码', validators=[EqualTo('password', message='两次密码不一致')]) email = StringField('邮箱', validators=[Email(message='邮箱格式不正确')]) submit = SubmitField('立即注册')
在视图函数中创建表单对象,然后分配到模板文件中并完成渲染
-
添加表单的验证逻辑,如下:
@user.route('/register/', methods=['GET', 'POST']) def register(): form = RegisterForm() if form.validate_on_submit(): # 根据表单数据,创建用户对象 # 将用户对象保存到数据库 # 发送用户账户的激活邮件 # 弹出flash消息提示用户 flash('用户已注册,请点击邮件中的链接以完成激活') # 跳转到首页/登录页面 return redirect(url_for('main.index')) return render_template('user/register.html', form=form)
-
添加用户模型,如下:
from app.extensions import db from werkzeug.security import generate_password_hash, check_password_hash class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(32), unique=True) password_hash = db.Column(db.String(128)) email = db.Column(db.String(64), unique=True) confirmed = db.Column(db.Boolean, default=False) # 保护密码属性 @property def password(self): raise AttributeError('密码是不可读属性') # 设置密码时,保存加密后的hash值 @password.setter def wrqf(self, password): self.password_hash = generate_password_hash(password) # 密码校验,正确返回True,错误返回False def verify_password(self, password): return check_password_hash(self.password_hash, password)
- 新建的模型必须在外部包含一次,否则项目根本不知道有这个模型,迁移失败;
- 创建或修改模型后记得及时完成迁移操作,以防模型与数据表不对应。
-
添加账户激活时的token生成与检验
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer class User(db.Model): ... # 生成账户激活的token def generate_activate_token(self, expires_in=3600): s = Serializer(current_app.config['SECRET_KEY'], expires_in=expires_in) return s.dumps({'id': self.id}) # 校验账户激活的token @staticmethod def check_activate_token(token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) except: return False u = User.query.get(data.get('id')) if not u: # flash('用户不存在') return False if not u.confirmed: # 账户没有激活 u.confirmed = True db.session.add(u) return True
-
完整注册实现,如下:
@user.route('/register/', methods=['GET', 'POST']) def register(): form = RegisterForm() if form.validate_on_submit(): # 根据表单数据,创建用户对象 u = User(username=form.username.data, password=form.password.data, email=form.email.data) # 将用户对象保存到数据库 db.session.add(u) # 因为下面生成token需要使用id,此时还没有,因此需要手动提交 db.session.commit() # 生成token token = u.generate_activate_token() # 发送用户账户的激活邮件 send_mail(u.email, '账户激活', 'email/activate', username=u.username, token=token) # 弹出flash消息提示用户 flash('用户已注册,请点击邮件中的链接以完成激活') # 跳转到首页/登录页面 return redirect(url_for('main.index')) return render_template('user/register.html', form=form)
-
添加激活邮件的模板
<h1>Hello {{ username }}</h1> <p>激活账户请点击右边链接<a href="{{ url_for('user.activate', token=token, _external=True) }}">激活</a></p>
-
添加邮件激活的路由
@user.route('/activate/<token>')
def activate(token):
if User.check_activate_token(token):
flash('账户已激活')
return redirect(url_for('user.login'))
else:
flash('激活失败')
return redirect(url_for('main.index'))
用户登录认证
-
添加登录的跳转链接
-
添加登录的视图函数
-
添加登录的模板文件
-
添加用户登录的表单
-
创建登录表单并在模板文件中渲染
-
登录检验,如下:
@user.route('/login/', methods=['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): u = User.query.filter_by(username=form.username.data).first() if not u: flash('无效的用户名') elif not u.confirmed: flash('账户尚未激活,请激活后再登录') elif u.r(form.password.data): flash('登录成功') return redirect(url_for('main.index')) else: flash('无效的密码') return render_template('user/login.html', form=form)
-
flask-login扩展库的使用,如下:
from flask_login import LoginManager login_manager = LoginManager() # 初始化对象 def config_extensions(app): ... # 登录管理初始化 login_manager.init_app(app) # 指定登录的端点 login_manager.login_view = 'user.login' # 指定登录的提示信息 login_manager.login_message = '需要登录才可访问' # 设置session的保护级别 # None:用于session保护;'basic':基本的;'strong':最严格的 # 要想完成记住我的功能,不能设置为'strong' login_manager.session_protection = 'strong' # 定制后就不会默认跳转到登录页面 @login_manager.unauthorized_handler def unauthorized(): return 'unauthorized'
另外,需要设置一个回调函数,用户模型继承自UserMixin,如下:
from flask_login import UserMixin class User(UserMixin, db.Model): pass # 登录认证的回调 @login_manager.user_loader def load_user(uid): return User.query.get(int(uid))
-
使用
# 登录指定的用户,顺便可以完成'记住我'的功能 # 可以指定过期时间,timedelta格式 from datetime import timedelta duration = timedelta(seconds=10) login_user(u, remember=form.remember.data, duration=duration)
-
添加不同状态的显示,如下:
{% if current_user.is_authenticated %} <li><a href="{{ url_for('user.logout') }}">退出</a></li> <li><a href="#">{{ current_user.username }}</a></li> {% else %} <li><a href="{{ url_for('user.register') }}">注册</a></li> <li><a href="{{ url_for('user.login') }}">登录</a></li> {% endif %}
-
路由保护
@user.route('/test/')
# 路由保护,需要登录才可访问
@login_required
def test():
return '登录后才可访问的页面'
登录成功之后的跳转:若get参数中有next则跳转到next位置,没有则跳转到首页
return redirect(request.args.get(‘next’) or url_for(‘main.index’))
-
flask-login总结
获取状态: is_authenticated:登录 is_anonymous: 匿名 改变状态: login_user:用户登录,顺便还可以完成'记住我'的功能 logout_user:退出登录 路由保护:保护那些需要登录才有权限访问的路由 login_required
用户信息管理
-
显示用户信息
1.修改登录后的导航条显示(下拉显示相关操作) 2.添加用户信息点击的跳转链接 3.添加对应的视图函数,渲染指定的模板文件 4.添加用户信息展示的模板文件,显示用户信息(可以参考bootstrap)
-
修改密码(练习)
-
修改邮箱(练习)
-
上传头像(练习)
万水千山总是情,点个关注行不行。
关注我,看下一篇flask