the flask mega tutorial自学记录 之 第五章 用户登录(注册和登录)

一、 密码hash化

1、 我们访问网站的时候,经常需要注册,注册以后自然就会存留密码。
为了防止意外数据外泄导致用户的密码暴露,故可以通过hash算法将用户密码加密处理。在第四章,我们在User model中就定义了这么一个字段,还没开始使用了。密码hash化其实是一个复杂的过程,不过,这些工作可以交给其他专家,我们只需要在APP应用中调用即可。
有一个此功能的第三方包:Werkzeug。这个包在flask安装的时候就一起安装好了。
加密:

from werkzeug.security import generate_password_hash
hash = generate_password_hash('foobar')   #将密码foobar通过hash算法加密

2 、有了加密,自然就会用到解密了。flask自带了一个密码检核的方法。
检核密码:

from werkzeug.security import check_password_hash
check_password_hash(hash, 'foobar')        #检核密码

3 、为了方便后期USER表的密码操作,可以在原有的USER类中新增密码hash及密码核对的方法

from werkzeug.security import generate_password_hash, check_password_hash

# ...

class User(db.Model):
    # ...
	#hash 明文password
    def set_password(self, password):
        self.password_hash = generate_password_hash(password)
	#检核密码
    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

4、验证下

#实例化用户信息
>>>u = User(username='susan', email='susan@example.com') 
>>>u.set_password('mypassword')
>>>u.check_password('anotherpassword')
False
>>>u.check_password('mypassword')
True

二、介绍Flask-Login

我给大家介绍一个flask中非常流行的扩展: Flask-Login。
这个扩展可以管理用户登录状态。例如:一个用户登录应用后跳转到制定的页面。它带有remember me的功能,即使用户在退出浏览器后,还会保留着登录信息。
1、安装此扩展

pip install flask-login

2、初始化Login
类似其他的扩展,需要先初始化,方便其他模块调用。
app/init.py:

# ...
from flask_login import LoginManager

app = Flask(__name__)
# ...
login = LoginManager(app)

# ...

三、为Flask-Login提前准备User模型

在用户登录的时候,我们经常需要获取用户登录的一些属性值来进一步判读下一步操作:
is_authenticated:是否认证过的
is_active:是否活跃账户.
is_anonymous: 是否匿名账户
get_id(): 返回用户的id.

我们可以很容易的实现上边的4个项通用功能。
flask_login包含的一个类UserMixin,这个类包含了很多适用于User模型类的通用功能。
User类继承UserMixin:

# ...
from flask_login import UserMixin
class User(UserMixin, db.Model):     #通过继承方式承接那些类属性
    # ...

四、用户加载函数

Flask-Login通过用户ID一直监控着登录用户。每次用户登录到一个新页面,Flask-Login就会重新获取用户的ID,随后把用户信息加载到内存中。
再匹配用户信息的时候,就需要先加载用户信息。
由于Flask-Login根本不知道数据库,所以,需要我们在APP应用中定义一个功能:通过用户ID来获取用户信息。
app/models.py

from app import login   #引用LoginManager(app)
# ...

@login.user_loader
def load_user(id):
    return User.query.get(int(id))     #通过int把id转换成数字

五、 用户登录

在用户注册界面,用户录入完成后,将要验证用户名称、密码信息。如果无误就跳转到首页。对于已经注册过的用户,就不能再导航到注册页。

app/routes.py

# ...
from flask_login import current_user, login_user
from app.models import User

# ...

@app.route('/login', methods=['GET', 'POST'])
def login():
    #如果是已经注册过的用户,直接跳转到首页
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = LoginForm()              #实例化登录表单
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()  #根据用户名查询对应用户的记录行
        if user is None or not user.check_password(form.password.data):    #如果登录信息不全及密码错误、用户名不对;提交后仍然停留在登录页面
            flash('Invalid username or password')
            return redirect(url_for('login'))             
        login_user(user, remember=form.remember_me.data)   #login_user(user),其实也是调用user_loads()把用户设置到session中
        return redirect(url_for('index'))
    return render_template('login.html', title='Sign In', form=form)

六、 注销账户

既然用户注册了,如果用户认为以后都不想再登录了,自然就会涉及到注销。
Flask-Login中有一个很好方法:logout_user() 。
app/routes.py

# ...
from flask_login import logout_user

# ...

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('index'))

为了方便用户注销,在导航栏中增加注销菜单项:

   <div>
        Microblog:
        <a href="{{ url_for('index') }}">Home</a>
        {% if current_user.is_anonymous %}   #判断当前用户是否匿名账户
        <a href="{{ url_for('login') }}">Login</a>
        {% else %}
        <a href="{{ url_for('logout') }}">Logout</a>
        {% endif %}
    </div>

七、要求用户注册后才能访问网页

有时页面或内容,需要会员或注册用户才可以查看,Flask可以很方便的实现此功能。如果没注册,在打开网页的时候回自动跳转到登录界面。
1、首页要告知Flask,那个视图函数是控制登录的。
app/init.py:

# ...
login = LoginManager(app)
login.login_view = 'login'   #login是视图函数名称

2、设置注册后访问
app/routes.py:

from flask_login import login_required

@app.route('/')
@app.route('/index')
@login_required      #强制注册装饰器
def index():
    # ...

3、 登录后跳转回原访问页面
@login_required作用:
跳转到登录页面,同时在页面URL中增添nex访问参数。

例如: URL /login?next=/index

from flask import request   #查询客户使用
from werkzeug.urls import url_parse    #判断域名使用

@app.route('/login', methods=['GET', 'POST'])
def login():
    # ...
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        #获取登录页面路由地址中的next参数值
        next_page = request.args.get('next')
        #url_parse编译路由地址,netloc属性指域名或服务器地址
        #当next_page为空或者路由地址是相对地址时,返回index网页,否则返回next_page制定页面(绝对的地址)
        if not next_page or url_parse(next_page).netloc != '':
            next_page = url_for('index')
        return redirect(next_page)
    # ...

八、在模板中显示当前用户

app/templates/index.html:

{% extends "base.html" %}

{% block content %}
    <h1>Hi, {{ current_user.username }}!</h1>   #返回当前用户名称
    {% for post in posts %}    #循环遍历当前用户的博文
    <div><p>{{ post.author.username }} says: <b>{{ post.body }}</b></p></div>
    {% endfor %}
{% endblock %}

备注:把以前手工建立的用户信息语句块删除,同时把index视图里边的渲染页面的user参数删除。

@app.route('/')
@app.route('/index')
def index():
    # ...
    return render_template("index.html", title='Home Page', posts=posts)

九、 用户注册

当在登录界面的时候,如果用户没有登录账号,就需要注册了。
1、 设置注册表单
app/forms.py

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
from app.models import User

# ...

class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired()])
    #Email()用于判断邮件名格式
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    password2 = PasswordField(
        'Repeat Password', validators=[DataRequired(), EqualTo('password')])   #EqualTo判断等于,注意要添加引号
    submit = SubmitField('Register')

    def validate_username(self, username):
        user = User.query.filter_by(username=username.data).first()
        if user is not None:
            raise ValidationError('Please use a different username.')

    def validate_email(self, email):
        user = User.query.filter_by(email=email.data).first()
        if user is not None:
            raise ValidationError('Please use a different email address.')

2、 设置注册页面html格式
app/templates/register.html:

{% extends "base.html" %}

{% block content %}
    <h1>Register</h1>
    <form action="" method="post">
        {{ form.hidden_tag() }}
        <p>
            {{ form.username.label }}<br>
            {{ form.username(size=32) }}<br>
            {% for error in form.username.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.email.label }}<br>
            {{ form.email(size=64) }}<br>
            {% for error in form.email.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.password.label }}<br>
            {{ form.password(size=32) }}<br>
            {% for error in form.password.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.password2.label }}<br>
            {{ form.password2(size=32) }}<br>
            {% for error in form.password2.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>{{ form.submit() }}</p>
    </form>
{% endblock %}

3、 在登录页面登录按钮下边增加一个跳转到注册页面的连接

<p>New User? <a href="{{ url_for('register') }}">Click to Register!</a></p>

4、定义注册视图函数
用户在注册后,把用户信息添加到数据库中。
db.session.add(user) :添加用户记录
db.session.commit():执行数据库操作

from app import db
from app.forms import RegistrationForm

# ...

@app.route('/register', methods=['GET', 'POST'])  #注意添加方法,否则点击登录按钮的时候会报错:不能使用POST方法。
def register():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Congratulations, you are now a registered user!')
        return redirect(url_for('login'))
    return render_template('register.html', title='Register', form=form)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值