flask注册之后邮箱确认功能的实现

来源:互联网 发布:淘宝交换友情链接 编辑:程序博客网 时间:2024/06/06 09:13

搞了半天终于可以正常运行了,但是还是感觉一团浆糊,总结一下,用户端要完成的操作是这样的:
1,注册(这时候数据库已经有用户的账户密码了,但是User.confirmed=False,这时是无法正常登陆的)
2,点开Email验证地址之前登陆(作者构建了一个中间状态路由,当用户注册之后但未确认时登陆就会被重定向到这个路由,这时APP保存了用户的登录状态(但是没有正常权限),之后再点击邮箱里的验证链接就可以验证成功了,不登录的话点击验证会抛出401错误的,因为验证路由(confirm)被@login_required上锁的,如果去掉@login_required的话也会报错,因为我们需要验证链接中的验证信息是否与注册的ID相同,相同才能注册,当然了,我们也可以直接拿链接中的验证信息解码之后的ID与数据库进行交互激活账号,但是这样安全系数较差,最好的办法是在用户注册之后实现自动登录,这样对用户比较友好),验证成功之后网页跳转到主页。
在用户操作的过程中,应用程序是怎么运行的?
1,接收用户的GET请求返回注册页面
2,用户填写资料之后接收用户POST请求重定向到登录页面

@auth.route('/register', methods=['GET', 'POST'])def register():    #注册    form = RegistrationForm()    if form.validate_on_submit():        user = User(email=form.email.data,                    username=form.username.data,                    password=form.password.data)        db.session.add(user)        db.session.commit()  #这里不能等数据库自动保存,因为用户在验证时需要登录        token = user.generate_confirmation_token()  #生成HASH码        send_email(user.email, 'Confirm Your Account',                    'auth/email/confirm', user=user, token=token)#发送验证信息        flash('邮件已经发送!')        return redirect(url_for('auth.login'))#重定向到登录页面    return render_template('auth/register.html', form=form)

在执行这一步的时候完成了以下两步操作
2.1,生成验证信息()

models.py

...from itsdangerous import TimedJSONWebSignatureSerializer as Serializer...class User(db.Model,UserMixin):...def generate_confirmation_token(self,expiration=3600):    s = Serializer(current_app.config['SECRET_KEY'], expiration)        #这个函数需要两个参数,一个密匙,从配置文件获取,一个时间,这里1小时    return s.dumps({'confirm':self.id})        #为ID生成一个加密签名,然后再对数据和签名进行序列化,生成令牌版字符串(就是一长串乱七八糟的东西),然后返回...

2.2,组装,发送验证信息()
email.py

#encoding:utf8from . import mailfrom flask_mail import Messagefrom flask import render_template, current_appdef send_email(to, subject, template, **kwargs):    app = current_app._get_current_object()#这里不太懂,牵扯到异步,反正是配置验证信息的    msg = Message(subject,sender='418836702@qq.com',recipients=[to])#实例化一个Message对象,准备发送邮件,接受者为to    msg.body = render_template(template + '.txt', **kwargs)    msg.html = render_template(template + '.html', **kwargs)#将准备好的模板添加到msg对象上,字典传的参里包括token(即生成的一长串字符串),链接的组装,页面的渲染在里面用jinja2语法完成    with app.app_context():        mail.send(msg) #发射

这时用户的页面已经跳转到登录页面,并且收到了邮件,假设他没瞎填,并且是一个很聪明的人,他这时就登录了,他登录之后程序干了什么呢?
3,首先肯定不可能让他直接登录成功,因为没激活,先滚去中间页面,这里作者用到了钩子,一般我们用@before_request,但是在蓝本全局中使用的话还是得用@before_app_request,不要问为什么,我也不知道,这个钩子的代码如下:

views.py@auth.before_app_requestdef before_request():    if current_user.is_authenticated \            and not current_user.confirmed \            and request.endpoint[:5] != 'auth.' \            and request.endpoint != 'static':        return redirect(url_for('auth.unconfirmed'))

这个钩子的作用是相当于梁山好汉,此路是我开,你满足我的条件你就听我的,这里三个条件:a,有用户登录着呢。b,这个用户没有验证,cd,是请求链接的端点信息,如果是这些东西赶紧放人家过去,人家有正事要干。最后跳转到这个路由:

@auth.route('/unconfirmed')def unconfirmed():    if current_user.is_anonymous or current_user.confirmed:        return redirect(url_for('main.index'))return render_template('auth/unconfirmed.html')

这就是那个中间路由,就像你进我家但是你没有激活,我把你关院子里不让你进来一样,但是这时程序中已经有你的登录session了,这个时候你再点击邮件里的链接就可以进房间了,并且执行激活操作了:

@auth.route('/confirm/<token>')@login_requireddef confirm(token):    if current_user.confirmed:        #如果你已经激活过了        return redirect(url_for('main.index'))    if current_user.confirm(token):        #去激活并且激活成功了        flash('O了!')    else:        flash('你是盗号的还是迟到鬼?')    return redirect(url_for('main.index'))

这一步中执行了激活操作:
models.py

class User(db.Model,UserMixin):...def confirm(self,token):    #激活    s = Serializer(current_app.config['SECRET_KEY'])    #传入和刚才一样的密匙,解码要用    try:        data = s.loads(token)#解码    except:        return False     if data.get('confirm') != self.id:        return False    self.confirmed = True #解的码和已经登录的账号ID相等时操作数据库改变User.confirmed的值为True    db.session.add(self)    return True #激活成功返回True...

齐活!
PS:flask-email的难点主要是在配置上,我这里用的是QQ邮箱,很久之前搞的,这里直接拿来用,改天总结下。

1 0
原创粉丝点击