8.5 用户注册时发送确认邮件功能——itsdangerous

__________________________________________________前言________________________________________________________

我们先来看上节的注册视图函数:

@auth.route('/register', methods=['GET', 'POST'])  
  
def register():  
  
    form = RegisterForm()  #创建表单  
  
    if form.validate_on_submit():  #填写的表单数据通过验证函数  
  
        u = User(email=form.email.data, username=form.username.data, password=form.password.data)  #创建用户  
  
        db.session.commit(u)  #把用户添加到会话  
  
        flash('You can now login.')  #提示用户已经可以登录  
  
        return redirect(url_for('auth.login'))  #重定向  
  
    return render_template('auth/register.html', form=form) 

    用户填写完注册表单点击提交按钮后, 会通过validate_on_submit验证, 然后创建该用户, 把该用户提交到会话。

    但此处存在一个问题, 我们不知道用户输入的email是不是有效的email, 我们到底能不能通过该email联系上用户, 所以我们要添加一个发送确认邮件的功能, 思路如下:

      1.用户注册以后, 我们先提交会话, 因为id是数据库分配的, 只有提交会话以后用户才有id;

      2.向用户发送一封确认邮件, 该邮件的主要内容是一含有用户id的确认链接,该链接映射确认函数;

      3.用户打开邮箱点击确认链接, 视图函数处理用户请求, 先要求用户登录——login_required,然后对照登录用户的id是否和链接中的id相同, 如果相同, 则验证成功, 把用户的confirm字段改为True。

————————————————————————————————————————————————————

    以上就是我们的思路, 但是考虑还不够周到:

     用户id比较容易猜测, 如果恶意用户知道了链接格式, 便可轻松确认任何用户, 所以我们要对用户id进行加密, 借助itsdangerous包把用户id加密成token字符串;

    在发送邮件之前生成token字符串, 点击链接之后验证token字符串就好了。

下面对我们的程序进行修改:

——————————————————————分界线——————————————————————————

一. 修改|-app/models.py

token是由用户id生成的, 验证的时候用户id是由token解密得到的, 所以生成token和验证token的函数应该放到User表中:

from . import db

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

from flask import current_app

class User(db.Model):

    #...

    confirm = db.Column(db.Boolean, default=False)  #添加验证字段

    def generate_token(self, expiration=3600):

        s = Serializer(current_app.config['SECRET_KEY'], expires_in=expiration)  #生成签名

        return s.dumps({'confirm': self.id})  #返回加密后的token字符串

    def confirm_token(self, token):

        s = Serializer(current_app.config['SECRET_KEY'])

        try:

            data = s.loads(token)  #解密token, 得到id字典

        except:

             return False

         if data.get('confirm') != self.id:  #如果token中的id不等于当前用户id, 验证失败

             return False

         self.confirm = True  #修改该用户的confirm字段

         db.session.add(user)  #把用户添加到会话里

         return True

*我们在User表中新加了confirm属性, 需要我们重新生成迁移脚本, 并把迁移应用到数据库中, 我们在前面的章节已经有介绍怎么做, 此处不再赘述。

二. 修改|-app/-auth/views.py

我们需要在注册视图里添加发送邮件的功能, 然后新增加一个确认路由:

from . import auth

from .forms import RegisterForm

from ..models import User

from .. import db

from ..email import send_mail

from flask import redirect, url_for, flash, render_template

from flask_login import login_required

@auth.route('/register', methods=['GET', 'POST'])

def register():

    form = RegisterForm()  #注册表单

    if form.validate_on_submit():  #用户提交的表单数据通过验证函数时为True

        user = User(email=form.email.data, username=form.username.data, password=form.password.data)

        db.session.add(user)

        db.session.commit()  #把会话提交到数据库中后用户才有id


        token = user.generate_token()  #生成token字符串

        send_mail(user.email, 'Confirm your account', 'auth/email/confirm',  user=user, token=token)  #向用户发确认邮件

        flash('a confirm email has been sent to your email.')

        return redirect(urll_for('main.index'))

     return render_template('auth/register', form=form)


@auth.route('/confirm/<token>')

@login_required

def confirm(token):

    if current_user.confirm:

        return redirect(url_for('main.index'))  #防止用户重复点击验证链接

    if current_user.confirm_token(token):  #无论验证成功与否, 都先提示用户然后返回主页

        flash('You have confirmed your account successfully.')

    else: 

       flash('Confirm failed.') 

    return redirect(url_for('main.index')) 

三. 修改|-app/templates/auth/email/confirm.txt

Dear  {{ user.username }}

Please click the link below to confirm your account:

{{ url_for('auth.confirm', token=token, _external=True) }}

confirm.html与.txt文件类似, 不再赘述。

*url_for生成的是相对地址, 只能用在程序网页的上下文中, 在邮箱中需要绝对地址, 所以把_external参数设置为True。


四. 效果演示

1.填写注册信息

2.我们点击提交以后, 发送post请求到register视图函数, 创建用户并提交到数据库:

3.发送邮件, 显示提示信息, 并重定向到主页:

4.打开邮箱, 发现有一封新邮件:

5.点击邮件的链接, 因为confirm视图函数有@login_required修饰器, 没有登陆也就没有得到访问该函数的授权,所以会重定向到登录页面:



6.填写完登录信息后, 点击提交按钮,

这时由auth.login视图函数处理post请求, login函数在验证完用户密码后返回重定向, 代码是——return redirect(request.args.get('next'or url_for('main.index')), 第一个参数的作用是存储上次用户访问的未授权的url, 也就是被login_required阻止访问的验证函数的url, 重新访问confirm函数, 通过验证, 数据库中用户的confirm字段被修改为1:


7.程序提示认证成功并返回主页:


*上面图片的文字介绍都是按照代码的执行顺序来解释的。



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值