Python Flask学习_确认账户(使用电子邮件)

用户的状态可以分为:未登录,登录但账户未确认和登录且账户确认。

目标是:

1.未登录。显示一个欢迎的页面:



2.登录但未确认。显示一个需要确认账户的页面和链接。


3.登录且账户确认:显示欢迎XXX的页面:


一、用户登录

# app/main/views.py

@main.route('/',methods=['GET','POST'])
def index():
    '''
    视图函数。主页。
    :return: 渲染后的模板
    '''
    return render_template('index.html')
# app/templates/index.html

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block title %}Flasky{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Hello,
        {% if current_user.is_authenticated %}                        #flask-login提供的current_user对象可用来确认状态
            {{ current_user.username }}
        {% else %}
            Stranger
        {% endif %}
        !
    </h1>
</div>

{% endblock %}

还记得我们之前说,要想使用flask-login扩展,必须实现的4个方法里就包括is_authenticated:如果用户已登录返回True,否则返回False。

这样,主页就分别针对是否登录,显示不同内容。

用户想要登录,需要点击右上角Log In。Log In的链接是在app/templates/base.html中实现的,用来被其他模板继承的。

# app/templates/base.html

{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="{{ url_for('main.index') }}">Flasky</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="{{ url_for('main.index') }}">Home</a></li>
            </ul>
            <ul class="nav navbar-nav navbar-right">
                {% if current_user.is_authenticated %}
                <li><a href="{{ url_for('auth.logout') }}">Log Out</a> </li>
                {% else %}
                <li><a href="{{ url_for('auth.login') }}">Log In</a> </li>
                {% endif %}
            </ul>
        </div>
    </div>
</div>
{% endblock %}
如果current_user.is_authenticated返回True,则显示Log Out,链接到auth.logout的URL。否则,显示Log In,链接到auth.login的URL。log in 和 log out我们在使用认证蓝本中讲过了。 点击打开链接

但是,有一点不同:需要在log in的页面,加入注册的链接。

# app/templdates/auth/login.html

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block title %}Flasky - Login{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Login</h1>
</div>
<div class="col-md-4">
    {{ wtf.quick_form(form) }}
    <p>
        New User?
        <a href="{{ url_for('auth.register') }}">
            Click Here to register
        </a>
    </p>
</div>
{% endblock %}
显示'Click Here to register',链接到注册的视图函数(auth.register)

二、用户注册

# app/auth/views.py

@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()  # 生成token必须要用到user.id,因此必须要先提交到数据库
        send_mail(user.email, '注册', 'auth/mail/confirm', user=user, token=token)
        flash('一份确认的邮件需要您到邮箱确认.')
        return redirect(url_for('main.index'))
    return render_template('auth/register.html', form=form)

register接受GET和POST两种请求。GET请求,则返回空表单的这也页面给用户POST请求,则更新到数据库,生成令牌,把令牌发送到注册邮箱,让用户点击包含令牌的链接进行确认,返回主页。

三、用户登录邮箱,进行确认

邮件的内容

# app/templates/auth/mail/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>

url_for('auth.confirm', token=token, _external=True   :   带有token(令牌)的URL被发给用户,_external参数为True则返回的是完整的URL,其中包含协议(http://或https://)、主机名和端口。

处理的视图函数是auth.confirm。

四、服务器进行用户确认

# app/auth/views.py

@auth.route('/confirm/<token>')
@login_required
def confirm(token):
    '''确认用户 带token的URL
    保护路由:只能在登录状态下执行'''
    if current_user.confirmed:
        return redirect(url_for('main.index'))
    if current_user.confirm(token):
        db.session.commit()
        flash('you have confirmed your account. thanks!')
    else:
        flash('the confirmation link is invalid or has expired.')
    return redirect(url_for('main.index'))

if current_user.confirmed: 如果用户已经确认过(用户多次点击链接),则什么也不干,返回主页。

current_user.confirm(token)进行用户确认。改动提交到数据库,显示一条flash消息。返回主页。

Flask-Login提供的@login_required修饰器会保护这个路由(只有登录状态下才能访问这个路由)。因此,用户点击确认邮件中的链接后,要先登录,然后才能执行这个视图函数。

五、决定为确认账户的权限

每个程序都可以决定用户未确认账户之前可以做哪些操作。比如 ,允许未确认的账户登录,但只显示一个页面,这也页面要求用户确认账户。

我们的想法是:有一个针对全局请求的钩子,用户登录但是未确认的任何访问都将被重定向至确认的页面。

# app/auth/views.py

@auth.before_app_request
def 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.before_app_request  : 这是可以应用到全局请求的钩子(只能应用到蓝本的是before_request),在访问其它视图函数前,都要经过此函数只需针对特定的情况(登录未确认)重定向到确认的页面即可。

    if current_user.is_authenticated and not current_user.confirmed \   :current_user登录但是没有确认
            and request.endpoint[:5] != 'auth.' \            #请求的端点不在此蓝本中(auth)
            and request.endpoint != 'static':                   #

        return redirect(url_for('auth.unconfirmed'))

return redirect(url_for('auth.unconfirmed'))   : 重定向至unconfrimed


来看 unconfirm

if current_user.is_anonymous or current_user.confirmed:

        return redirect(url_for('main.index'))               :如果用户是管理员或者用户已经确认,直接返回主页。

return render_template('auth/unconfirmed.html')   :其他情况返回unconfirmed.html


在unconfirmed.html中提供重新确认账户的链接:

# app/templates/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 }}                                                      <!--current_user可以直接用-->
    </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>                    #链接到auth.resend_confirmation
    </p>
</div>
{% endblock %}

# app/auth/views.py

@auth.route('/confirm')
@login_required
def resend_confirmation():
    '''保护路由。处理未认证的用户重新进行认证'''
    token = current_user.generate_confirmation_token()
    send_mail(current_user.email, '确认您的账户', 'auth/mail/confirm', user=current_user, token=token)
    flash('一封确认邮件已经发送到您的邮箱,请确认。')
    return redirect(url_for('main.index'))

















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值