在我学习用户身份验证的时候,我发现这里有个小弊端,在用户注册完成后想要验证邮箱的时候,点击邮箱中的网址进行验证,此时还要登陆,这及其不符合我们的习惯。一般情况下我们只需要点击网址就可以验证成功并且进入到登录界面了。这是因为在确认路由中有login_required装饰器。
@auth.route('/confirm') @login_required //就是它 def resend_confirmation(): token = current_user.generate_confirmation_token() send_email(current_user.email, 'Confirm Your Account', 'auth/email/confirm', user=current_user, token=token) flash('A new confirmation email has been sent to you by email.') return redirect(url_for('main.index'))
所以我要把登录装饰器去了,在确认接口这里我改成需要传入两个参数,一个是token值,另一个就是用户唯一标识符,这里我选择用了id作为用户唯一标识符,来判断“是哪个人在验证他的身份”,当然如果你觉得 id 不安全的话也可以改成 username或者email,总之改完的代码变成这样
@auth.route('/confirm/<token>/<id>') def confirm(token, id): user = User.query.filter(User.id == id).first() if user.confirmed: return redirect(url_for('main.index')) if user.confirm(token): db.session.commit() flash('恭喜您! {}!你已经确认了你的账户!请登录!'.format(user.username)) else: flash('验证链接不正确或者超时') return redirect(url_for('auth.login'))
这里先把传过来的id接收,放到数据库里面进行比对,找到该用户(按理来说不存在找不到用户的情况,因为在注册后用户就被加入到数据库了,所以这里不必要写user不存在的情况)。先判断用户数是不是已经确认过了(conmfirmed为1),如果不是就验证token,这里的db.session.commit()提交的是confirmed的值,可以看一下User里面的confirm方法
# 验证token def confirm(self, token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token.encode('utf-8')) except: return False if data['confirm'] != self.id: return False self.confirmed = True db.session.add(self) return True
再调用confirm方法后,如果token被验证成功,就会将user对象的confirmed设置为1(默认一直是0),然后在方法中add,在confirm函数中commit,这样我们就知道了是哪个人在验证。验证完成后重定向到登录界面。当然,在用户发送的邮件也需要改变,只要在url()后面多加上一个参数即可。这样用户就会重定向到我们的路由
<p>亲爱的 {{ user.username }},</p> <p><b>欢迎来到我的博客!</b></p> <p>为了确认您的信息 <a href="{{ url_for('auth.confirm', token=token,id=user.id, _external=True) }}">请点击这儿</a>.</p> <p>当然,您也可以通过输入下面的网址进入</p> <p>{{ url_for('auth.confirm', token=token,id=user.id, _external=True) }}</p> <p>您亲爱的bolg主,</p> <p>TXS</p> <p><small>ps:不用回复</small></p>
这样我们就完成了对验证方式的改进。