flask web开发-用户验证代码分析(五)

来源:互联网 发布:淘宝预定手办确认收货 编辑:程序博客网 时间:2024/06/05 04:00

前几篇博文写过登录表单,登录验证,注册表单等,现在写一下用户注册,邮箱验证的部分,顺便梳理下整个过程.
app/auth/views.py

@auth.route('/register', methods=['GET', 'POST'])def register():    form=RegisterationForm()#注册表单拷贝给form    if form.validata_on_submit():#如果提交通过       user = User(email=form.eamil.data,                   username=form.username.data,                   password=form.password.data)       db.session.add(user)       token=user.ganerate_confirmation_token()#把id生成的令牌拷贝给token       send_email(user.email,'Confirm Your Account')#发送邮件验证       flash('A confirmation email has been sent to you by email.')       return redirect(url_for('auth.login'))#发送验证后页面跳转到登录页面    return render_template('auth/register.html', form=form)#如果提交失败,那么再次渲染注册页面.        

那接下里怎么才能知道用户点击链接确认了呢,先来看看发送的信息吧.
confirm.html

<p>Dear {{ user.username }},</p><p>Welcome to <b>Flasky</b>!</p><p>To confirm your account please <a href="{{ url_for('auth.confirm', token=token, _external=True) }}">click here</a>.</p><p>Alternatively, you can paste the following link in your browser's address bar:</p><p>{{ url_for('auth.confirm', token=token, _external=True) }}</p><p>Sincerely,</p><p>The Flasky Team</p><p><small>Note: replies to this email address are not monitored.</small></p>

一个电子邮件需要两个模板,分别用于渲染纯文本正文和富文本正文,所以下面是文本信息,confirm.txt

Dear {{ user.username }},Welcome to Flasky!To confirm your account please click on the following link:{{ url_for('auth.confirm', token=token, _external=True) }}Sincerely,The Flasky TeamNote: replies to this email address are not monitored.

_external=True这个函数就是生成链接的关键参数,生成完整的 URL,其中包含协议(http://或 https://)、主机名和端口。用户点击链接后,服务器怎么接受信息呢,看下面的代码

 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        db.session.add(self)        return True

上面的代码是modles.py中的一段验证时关于数据库操作的代码,看到了loads函数.从本博文的第一段代码可以看到,其实在发送的邮箱验证链接中有用户的id号生成的令牌token.当用户点击链接访问auth.confirm.这里一个关键的函数loads,可以把用户点击链接返回的token转换为id然后和数据库中的数据比对,如果匹配那么就把用户信息加入数据库(其实注册时已经加入了),最后函数返回true即验证通过.接下来就需要路由函数来提供跳转的路径了.

@auth.route('/confirm/<token>')@login_requireddef confirm(token):    if current_user.confirmed:        return redirect(url_for('main.index'))    if current_user.confirm(token):        flash('You have confirmed your account. Thanks!')#用户验证后显示的信息    else:        flash('The confirmation link is invalid or has expired.')    return redirect(url_for('main.index'))

上面的代码中修饰器@login_required保护路由函数,在验证后会让用户登录,如果用户已经验证过直接跳转到主页.
当然,如果用户没有验证成功或者没有验证,登录网页时需要路由函数来进行跳转到有未验证提示信息的页面,用户可以再次获取验证邮件.这个功能需要在登录验证失败后被拦截路由函数跳转到未验证的页面,页面中一定有再次发送验证邮件的链接或者按钮,链接的Url对应另一个路由函数来实现再次发送邮件的功能.
拦截路由函数before_request,在flask中叫钩子,就是连接上文的作用,如果想在蓝本中实现针对程序全局请求的钩子,就需要用到修饰器@before_app_request.

@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'))@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')#未验证函数返回未验证的页面

auth/unconfirmed.html

{% extends "base.html" %}{% block title %}Flasky - Confirm your account{% endblock %}{% block page_content %}<div class="page-header">    <h1>        Hello, {{ current_user.username }}!    </h1>    <h3>You have not confirmed your account yet.</h3>    <p>        Before you can access this site you need to confirm your account.        Check your inbox, you should have received an email with a confirmation link.    </p>    <p>        Need another confirmation email?        <a href="{{ url_for('auth.resend_confirmation') }}">Click here</a> ##给出再次发送邮件的链接,链接为路由函数resend_confirmation    </p></div>{% endblock %}路由函数resend_confirmation
@auth.route('/confirm')@login_required    #保护路由函数,只有再次之前登录了才能调用这个路由def resend_confirmation():    token = current_user.generate_confirmation_token()#id产生的令牌拷贝给实参token    send_email(current_user.email, 'Confirm Your Account',               'auth/email/confirm', user=current_user, token=token)#发送邮件函数,使用当前验证用户的邮箱,发送的邮件内容为auth/email/confirm    flash('A new confirmation email has been sent to you by email.')#发送后显示一行信息    return redirect(url_for('main.index'))#重定向到首页.