8.5 用户注册时发送确认邮件功能——itsdangerous
2018-03-18 17:13
525 查看
__________________________________________________前言________________________________________________________
我们先来看上节的注册视图函数:
@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字符串就好了。
下面对我们的程序进行修改:
——————————————————————分界线——————————————————————————
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) #生成签名
4000
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属性, 需要我们重新生成迁移脚本, 并把迁移应用到数据库中, 我们在前面的章节已经有介绍怎么做, 此处不再赘述。
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'))
confirm.html与.txt文件类似, 不再赘述。
*url_for生成的是相对地址, 只能用在程序网页的上下文中, 在邮箱中需要绝对地址, 所以把_external参数设置为True。
1.填写注册信息
4.打开邮箱, 发现有一封新邮件:
6.填写完登录信息后, 点击提交按钮,
这时由auth.login视图函数处理post请求, login函数在验证完用户密码后返回重定向, 代码是——return redirect(request.args.get('next') or url_for('main.index')), 第一个参数的作用是存储上次用户访问的未授权的url, 也就是被login_required阻止访问的验证函数的url, 重新访问confirm函数, 通过验证, 数据库中用户的confirm字段被修改为1:
*上面图片的文字介绍都是按照代码的执行顺序来解释的。
我们先来看上节的注册视图函数:
@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 dbfrom 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) #生成签名
4000
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 authfrom .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.程序提示认证成功并返回主页:
*上面图片的文字介绍都是按照代码的执行顺序来解释的。
相关文章推荐
- spring boot 整合 mail 发送邮件 【用户注册以及找回密码】
- 一个发送邮件功能,用户反映没有收到邮件,如何处理bug
- 新用户注册,新订单生成,在给客户发送邮件的同时,也给管理员发送邮件
- 网上商城之用户注册发送邮件激活
- 注册的时候发送确认邮件
- 购物网站20:用户/顾客action----用户列表---用户退出---用户管理---用户登录---用户注册---修改密码---发送邮件
- 实现用户注册时,向其油箱发送激活码邮件,并进行状态处理
- MVC使用ASP.NET Identity 2.0实现用户身份安全相关功能,比如通过短信或邮件发送安全码,账户锁定等
- WordPress用户注册无法发送密码邮件怎么回事?
- 在WordPress中注册新用户时无法收到确认邮件的问题
- 写一个实现用户注册时,向其邮箱发送激活码邮件,并进行状态处理。
- 实现注册时和绑定邮箱时发送邮件来确认绑定
- ecshop二次开发——新注册用户后台确认功能
- Java用户注册服务器发送短信验证码功能实现
- 实现用户注册时,向其油箱发送激活码邮件,并进行状态处理
- JAVA web 学习笔记三 向注册用户发送验邮件
- asp.net实现一个用户进行注册的时候同时发送一个邮件到注册人的邮箱,通过发送的邮箱链接来激活该帐号
- 用户注册 邮件激活验证的功能
- SAE平台搭建wordpress实现注册用户发送邮件
- SAE平台搭建wordpress实现注册用户发送邮件