最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

在Python的Flask框架中驗證注冊用戶的Email的方法

 更新時間:2015年09月02日 16:13:25   投稿:goldensun  
這篇文章主要介紹了在Python的Flask框架中驗證注冊用戶的Email的方法,包括非常詳細的測試過程,極力推薦!需要的朋友可以參考下

本教程詳細介紹在用戶注冊過程中如何去驗證他們的email地址。

工作流程上來講,在用戶注冊一個新賬戶后會寄送一個確認(rèn)信。直到用戶按指示完成了郵件中的“驗證”,否則他們的賬戶會一直處于“未驗證”狀態(tài)。這是大多數(shù)網(wǎng)絡(luò)應(yīng)用會采用的工作流程。

這當(dāng)中很重要的一件事就是,未驗證的用戶有什么權(quán)限?或者說,對于你的應(yīng)用,他們是有全部權(quán)限呢,還是被限制的權(quán)限呢,還是根本沒有權(quán)限?對于本教程中的應(yīng)用,未驗證用戶會在登錄后進到一個頁面,會提醒他們只有驗證了賬戶才可以進入應(yīng)用。

開始前說明一下,很多我們要增加的功能是Flask-用戶和Flask-安全的擴展部分——問題來了,為什么不直接用這兩個擴展呢?嗯,首先,這是個學(xué)習(xí)機會。同時,這倆擴展都有局限性,比如支持的數(shù)據(jù)庫。要是你想用RethinkDB怎么辦呢?
我們開始吧

Flask基本注冊

我們將會要開始一Flask樣例,這包括了用戶基本注冊。從這個github倉庫獲取代碼庫。一旦你創(chuàng)建和激活了virtualenv,運行下面的命令來快速開始:

$ pip install -r requirements.txt
$ export APP_SETTINGS="project.config.DevelopmentConfig"
$ python manage.py create_db
$ python manage.py db init
$ python manage.py db migrate
$ python manage.py create_admin
$ python manage.py runserver

在應(yīng)用運行的狀態(tài)下,訪問http://localhost:5000/register頁面,注冊一個新用戶。注意,注冊之后應(yīng)用會自動登陸,引導(dǎo)你進入主頁面。大概看一下,然后運行代碼——尤其是user這個藍圖(Blueprint是flask的一個概念)。

完成時停止服務(wù)器。

更新當(dāng)前應(yīng)用

模型

首先,我們來在我們project/models.py中的User模型里添加上confirmed字段:

class User(db.Model):
 
 __tablename__ = "users"
 
 id = db.Column(db.Integer, primary_key=True)
 email = db.Column(db.String, unique=True, nullable=False)
 password = db.Column(db.String, nullable=False)
 registered_on = db.Column(db.DateTime, nullable=False)
 admin = db.Column(db.Boolean, nullable=False, default=False)
 confirmed = db.Column(db.Boolean, nullable=False, default=False)
 confirmed_on = db.Column(db.DateTime, nullable=True)
 
 def __init__(self, email, password, confirmed,
   paid=False, admin=False, confirmed_on=None):
 self.email = email
 self.password = bcrypt.generate_password_hash(password)
 self.registered_on = datetime.datetime.now()
 self.admin = admin
 self.confirmed = confirmed
 self.confirmed_on = confirmed_on

注意此區(qū)域是怎樣默認(rèn)成“False”的。還要添加個confirmed_on字段,那是個datetime。為了用隊列分析來分析registered_on和confirmed_on日期的不同,所以我想包含這個datetime。

讓我們完全從頭開始創(chuàng)建數(shù)據(jù)庫并遷移吧!所以,先刪除數(shù)據(jù)庫dev.sqlite,以及“遷移”文件夾。

控制命令

接下來,在manage.py中,更新create_admin命令,使新的數(shù)據(jù)庫字段生效:

@manager.command
def create_admin():
 """Creates the admin user."""
 db.session.add(User(
 email="ad@min.com",
 password="admin",
 admin=True,
 confirmed=True,
 confirmed_on=datetime.datetime.now())
 )
 db.session.commit()

要確保導(dǎo)入datetime。現(xiàn)在,先再一次運行下面的指令:

$ python manage.py create_db
$ python manage.py db init
$ python manage.py db migrate
$ python manage.py create_admin

register()視圖函數(shù)

最后,在我們再次注冊用戶之前,我們需要改一下project/user/views.py中的register()視圖函數(shù)……

user = User(
 email=form.email.data,
 password=form.password.data
)

改成下面的:

user = User(
 email=form.email.data,
 password=form.password.data,
 confirmed=False
)

明白了嗎?思考下為什么要把confirmed默認(rèn)成False。

嗯好。再運行一遍應(yīng)用。轉(zhuǎn)入到http://localhost:5000/register,再注冊一個新用戶。如果你在SQLite瀏覽器中打開了你的SQLite數(shù)據(jù)庫,你會看到:

那么,這個我新注冊的用戶,michael@realpython.com沒有被驗證。讓我們驗證它。

添加email驗證

產(chǎn)生驗證令牌

郵件驗證應(yīng)包含一個特殊URL,使得用戶只需簡單地點擊它,即可驗證他/她的賬戶。理想情況下,這個URL應(yīng)該看起來像這樣–http://yourapp.com/confirm/<id>。這里的關(guān)鍵是它id。在這個id中用itsdangerous包,編碼用戶的郵件(包含時間戳)。

創(chuàng)建一個叫project/token.py的文件,添加下面的代碼:

# project/token.py
 
from itsdangerous import URLSafeTimedSerializer
 
from project import app
 
def generate_confirmation_token(email):
 serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])
 return serializer.dumps(email, salt=app.config['SECURITY_PASSWORD_SALT'])
 
def confirm_token(token, expiration=3600):
 serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])
 try:
 email = serializer.loads(
  token,
  salt=app.config['SECURITY_PASSWORD_SALT'],
  max_age=expiration
 )
 except:
 return False
 return email

所以在generate_confirmation_token()函數(shù)中,通過URLSafeTimedSerializer用在用戶注冊時得到的email地址生成一個令牌。那個_真實的_email在令牌中被編了碼。確認(rèn)令牌之后,在confirm_token()函數(shù)中,我們可以用loads()方法,它接管令牌和其過期時間——一個小時(3600秒)內(nèi)有效——作為參數(shù)。只要令牌沒過期,那它就會返回一個email。

在應(yīng)用的配置中(BaseConfig()),確保添加SECURITY_PASSWORD_SALT:

SECURITY_PASSWORD_SALT = 'my_precious_two'

更新register()視圖函數(shù)

現(xiàn)在再從project/user/views.py更新下register()視圖函數(shù):

@user_blueprint.route('/register', methods=['GET', 'POST'])
def register():
 form = RegisterForm(request.form)
 if form.validate_on_submit():
 user = User(
  email=form.email.data,
  password=form.password.data,
  confirmed=False
 )
 db.session.add(user)
 db.session.commit()
 
 token = generate_confirmation_token(user.email)

也是,要確保更新了這些導(dǎo)入模塊:

from project.token import generate_confirmation_token, confirm_token

處理Email驗證

接下來,添加個新的視圖來解決email驗證:

@user_blueprint.route('/confirm/<token>')
@login_required
def confirm_email(token):
 try:
 email = confirm_token(token)
 except:
 flash('The confirmation link is invalid or has expired.', 'danger')
 user = User.query.filter_by(email=email).first_or_404()
 if user.confirmed:
 flash('Account already confirmed. Please login.', 'success')
 else:
 user.confirmed = True
 user.confirmed_on = datetime.datetime.now()
 db.session.add(user)
 db.session.commit()
 flash('You have confirmed your account. Thanks!', 'success')
 return redirect(url_for('main.home'))

把這個添加到project/user/views.py。同樣,確保更新了這些導(dǎo)入:

import datetime
現(xiàn)在我們通過令牌調(diào)用confirm_token()函數(shù)。如果成功,我們更新用戶,把email_confirmed屬性改成True, 設(shè)置datetime為驗證發(fā)生的時間。還有,要是用戶已經(jīng)進行過一遍驗證過程了——而且已經(jīng)驗證了——我們要提醒用戶這點。

創(chuàng)建email模板

接著,添加一個基礎(chǔ)email模板:

<p>Welcome! Thanks for signing up. Please follow this link to activate your account:</p>
<p><a href="{{ confirm_url }}">{{ confirm_url }}</a></p>
<br>
<p>Cheers!</p>

把這個在“project/templates/user”中存為activate.html。這用了一個簡單叫confirm_url的變量,它會在register()視圖函數(shù)中被創(chuàng)建。

發(fā)送郵件

通過已經(jīng)安裝了而且設(shè)置在project/__init__.py中的Flask-Mail的一點兒幫助來創(chuàng)建一個基本函數(shù)來發(fā)送郵件。

創(chuàng)建一個叫email.py的文件:

# project/email.py
 
from flask.ext.mail import Message
 
from project import app, mail
 
def send_email(to, subject, template):
 msg = Message(
 subject,
 recipients=[to],
 html=template,
 sender=app.config['MAIL_DEFAULT_SENDER']
 )
 mail.send(msg)

在“project”文件夾中存一下。

所以,我們只要簡單地去處理收件人列表,主題,模板即可。我們會一點一點處理郵件配置的設(shè)置。

在project/user/views.py中(再次!)更新register()視圖函數(shù)

@user_blueprint.route('/register', methods=['GET', 'POST'])
def register():
 form = RegisterForm(request.form)
 if form.validate_on_submit():
 user = User(
  email=form.email.data,
  password=form.password.data,
  confirmed=False
 )
 db.session.add(user)
 db.session.commit()
 
 token = generate_confirmation_token(user.email)
 confirm_url = url_for('user.confirm_email', token=token, _external=True)
 html = render_template('user/activate.html', confirm_url=confirm_url)
 subject = "Please confirm your email"
 send_email(user.email, subject, html)
 
 login_user(user)
 
 flash('A confirmation email has been sent via email.', 'success')
 return redirect(url_for("main.home"))
 
 return render_template('user/register.html', form=form)

還要添加下面的導(dǎo)入模塊:

from project.email import send_email
我們在這里將所有的東西整合到一起。這個函數(shù)基本功能是作為控制器(直接或間接):

  • 處理最初注冊,
  • 產(chǎn)生令牌和確認(rèn)URL,
  • 寄送確認(rèn)email,
  • 快速驗證,
  • 用戶登入,
  • 更改用戶。

你注意到_external=True參數(shù)了嗎?這增加了包含了hostname和port(在我們情況中,http://localhost:5000)的完整URL。

在我們測試這個之前,我們要去設(shè)定郵件設(shè)置。

郵件

在project/config.py中更新BaseConfig():

class BaseConfig(object):
 """Base configuration."""
 
 # main config
 SECRET_KEY = 'my_precious'
 SECURITY_PASSWORD_SALT = 'my_precious_two'
 DEBUG = False
 BCRYPT_LOG_ROUNDS = 13
 WTF_CSRF_ENABLED = True
 DEBUG_TB_ENABLED = False
 DEBUG_TB_INTERCEPT_REDIRECTS = False
 
 # mail settings
 MAIL_SERVER = 'smtp.googlemail.com'
 MAIL_PORT = 465
 MAIL_USE_TLS = False
 MAIL_USE_SSL = True
 
 # gmail authentication
 MAIL_USERNAME = os.environ['APP_MAIL_USERNAME']
 MAIL_PASSWORD = os.environ['APP_MAIL_PASSWORD']
 
 # mail accounts
 MAIL_DEFAULT_SENDER = 'from@example.com'

查看 official Flask-Mail documentation 以得到更多信息
如果你已經(jīng)有了GMAIL賬號,那你可以用它或者注冊一個測試用GMAIL賬戶。然后把環(huán)境變量暫時設(shè)置在當(dāng)前shell中:

$ export APP_MAIL_USERNAME="foo"
$ export APP_MAIL_PASSWORD="bar"

如果你GMAIL賬號有兩步授權(quán), Google會屏蔽掉它。
現(xiàn)在開始測試!

第一個測試

打開應(yīng)用,轉(zhuǎn)入到 http://localhost:5000/register。然后用你能登陸的email地址注冊。順利的話,你應(yīng)該會收到封email,看起來像這樣:

點擊URL,你會轉(zhuǎn)到 http://localhost:5000/。保證用戶在數(shù)據(jù)庫里,那‘confirmed'字段是True,有個datetime和confirmed_on字段綁定在一起。

好!

處理許可

如果你記得,在教程的開始部分,我們決定了“未驗證用戶可以登錄但是他們會立刻被轉(zhuǎn)入一個頁面——我們稱之為/unconfirmed路徑——提醒用戶需要驗證賬戶才能使用應(yīng)用”。

所以,我們要——

  • 添加/unconfirmed路徑
  • 添加unconfirmed.html模板
  • 更新register()視圖函數(shù)
  • 創(chuàng)建裝飾器
  • 更新navigation.html模板
  • 添加/unconfirmed路徑

添加下面的路徑project/user/views.py:

@user_blueprint.route('/unconfirmed')
@login_required
def unconfirmed():
 if current_user.confirmed:
 return redirect('main.home')
 flash('Please confirm your account!', 'warning')
 return render_template('user/unconfirmed.html')

你看過類似的代碼,所以我們繼續(xù)。

添加unconfirmed.html模板

{% extends &quot;_base.html&quot; %}
 
{% block content %}
 
&lt;h1&gt;Welcome!&lt;/h1&gt;
&lt;br&gt;
&lt;p&gt;You have not confirmed your account. Please check your inbox (and your spam folder) - you should have received an email with a confirmation link.&lt;/p&gt;
&lt;p&gt;Didn&#039;t get the email? &lt;a href=&quot;/&quot;&gt;Resend&lt;/a&gt;.&lt;/p&gt;
 
{% endblock %}

在“project/templates/user”中,把這個存為 unconfirmed.html 。這次應(yīng)該直截了當(dāng)?,F(xiàn)在,為了重新寄送驗證email,就只加了一個假的URL。我們接下來會解決它的。

更新register()視圖函數(shù)

現(xiàn)在簡單地把:

return redirect(url_for("main.home"))

變成:

return redirect(url_for("user.unconfirmed"))

所以,送完驗證email后,用戶會進入/unconfirmed路徑。

創(chuàng)建裝飾器

# project/decorators.py
 
from functools import wraps
 
from flask import flash, redirect, url_for
from flask.ext.login import current_user
 
def check_confirmed(func):
 @wraps(func)
 def decorated_function(*args, **kwargs):
 if current_user.confirmed is False:
  flash('Please confirm your account!', 'warning')
  return redirect(url_for('user.unconfirmed'))
 return func(*args, **kwargs)
 
 return decorated_function

這里我們用一個基本函數(shù)去檢查用戶是否驗證。如果未驗證,用戶會進入/unconfirmed路徑。在“project”目錄中,把這個存為decorators.py。

現(xiàn)在裝飾 profile() 視圖函數(shù):

@user_blueprint.route('/profile', methods=['GET', 'POST'])
@login_required
@check_confirmed
def profile():
 ... snip ...

確保導(dǎo)入裝飾器:

from project.decorators import check_confirmed

更新 navigation.html 模板

最后,更新navigation.html模板接下來的部分——

把:

&lt;ul class=&quot;nav navbar-nav&quot;&gt;
 {% if current_user.is_authenticated() %}
 &lt;li&gt;&lt;a href=&quot;{{ url_for(&#039;user.profile&#039;) }}&quot;&gt;Profile&lt;/a&gt;&lt;/li&gt;
 {% endif %}
&lt;/ul&gt;

變成:

&lt;ul class=&quot;nav navbar-nav&quot;&gt;
 {% if current_user.confirmed and current_user.is_authenticated() %}
 &lt;li&gt;&lt;a href=&quot;{{ url_for(&#039;user.profile&#039;) }}&quot;&gt;Profile&lt;/a&gt;&lt;/li&gt;
 {% elif current_user.is_authenticated() %}
 &lt;li&gt;&lt;a href=&quot;{{ url_for(&#039;user.unconfirmed&#039;) }}&quot;&gt;Confirm&lt;/a&gt;&lt;/li&gt;
 {% endif %}
&lt;/ul&gt;

又該測試了!

第二次測試

打開應(yīng)用,再次用能登陸的email地址注冊。(可以隨便從數(shù)據(jù)庫刪除你之前注冊的老用戶,這樣可以再用一遍)現(xiàn)在,注冊完會轉(zhuǎn)入http://localhost:5000/unconfirmed。

確保測試了http://localhost:5000/profile路徑。這會使你轉(zhuǎn)到http://localhost:5000/unconfirmed。

驗證email,你就會有完整頁面的權(quán)限了。快去把!

重寄送email

最后,來做重新寄送的鏈接。增加下面的視圖函數(shù)到project/user/views.py:

@user_blueprint.route('/resend')
@login_required
def resend_confirmation():
 token = generate_confirmation_token(current_user.email)
 confirm_url = url_for('user.confirm_email', token=token, _external=True)
 html = render_template('user/activate.html', confirm_url=confirm_url)
 subject = "Please confirm your email"
 send_email(current_user.email, subject, html)
 flash('A new confirmation email has been sent.', 'success')
 return redirect(url_for('user.unconfirmed'))

現(xiàn)在更新unconfirmed.html 模板:

{% extends &quot;_base.html&quot; %}
 
{% block content %}
 
&lt;h1&gt;Welcome!&lt;/h1&gt;
&lt;br&gt;
&lt;p&gt;You have not confirmed your account. Please check your inbox (and your spam folder) - you should have received an email with a confirmation link.&lt;/p&gt;
&lt;p&gt;Didn&#039;t get the email? &lt;a href=&quot;{{ url_for(&#039;user.resend_confirmation&#039;) }}&quot;&gt;Resend&lt;/a&gt;.&lt;/p&gt;
 
{% endblock %}

第三次測試

你知道這次的演練內(nèi)容了,這次保證去重新寄送一個新的確認(rèn)email,測試鏈接。應(yīng)該沒問題。

最后,如果你給自己發(fā)好幾個驗證信,會發(fā)生什么? 每封都有效嗎?測試一下。注冊個新用戶,寄送一些新的驗證信。驗證第一封試試。它可以嗎?它應(yīng)該可以。這樣行嗎?你是否認(rèn)為要是新的寄出,其他email應(yīng)該失效呢?

對這種事做些調(diào)查。測試下你用的其他網(wǎng)頁應(yīng)用。它們是怎么處理這種行為的?

更新測試套件

好的。這是為了主要功能。我們更新當(dāng)前測試套件怎么樣?因為它,嗯,有問題。

運行測試:

$ python manage.py test

你會看到下面的錯誤:

TypeError: __init__() takes at least 4 arguments (3 given)

要去改正它,只需要在project/util.py中更新setUp()方法:

def setUp(self):
 db.create_all()
 user = User(email="ad@min.com", password="admin_user", confirmed=False)
 db.session.add(user)
 db.session.commit()


測試之前,在tests/test_models.py中,注釋一下test_user_registration()測試,因為我們不想為了這個測試真 的發(fā)送一封郵件。

現(xiàn)在再測試一下。應(yīng)該全能通過!

結(jié)論

還可以做更多的:

  • 富文本 vs. 純文本email——應(yīng)該都寄出。
  • 重設(shè)定密碼email——當(dāng)用戶忘記密碼時,這些應(yīng)該被寄出。
  • 用戶管理——應(yīng)該允許用戶更新email和密碼,當(dāng)email變了的話,應(yīng)該重新驗證一遍。
  • 測試——需要寫更多測試來涉及更多新功能,包含用mock/patch更新的test_user_registration(),來防止實際email被發(fā)送。

相關(guān)文章

  • python讀取圖片的方式,以及將圖片以三維數(shù)組的形式輸出方法

    python讀取圖片的方式,以及將圖片以三維數(shù)組的形式輸出方法

    今天小編就為大家分享一篇python讀取圖片的方式,以及將圖片以三維數(shù)組的形式輸出方法,具有好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07
  • python神經(jīng)網(wǎng)絡(luò)特征金字塔FPN原理

    python神經(jīng)網(wǎng)絡(luò)特征金字塔FPN原理

    這篇文章主要為大家介紹了python神經(jīng)網(wǎng)絡(luò)特征金字塔FPN原理的解釋,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • python 實現(xiàn)判斷ip連通性的方法總結(jié)

    python 實現(xiàn)判斷ip連通性的方法總結(jié)

    下面小編就為大家分享一篇python 實現(xiàn)判斷ip連通性的方法總結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-04-04
  • python?存儲變量的幾種方法(推薦)

    python?存儲變量的幾種方法(推薦)

    這篇文章主要介紹了python?存儲變量的幾種方法,包括numpy?自帶方法,pandas?自帶方法,sklearn?的自帶方法和pickle?庫操作方法,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-11-11
  • python的格式化輸出(format,%)實例詳解

    python的格式化輸出(format,%)實例詳解

    Python中格式化字符串目前有兩種陣營:%和format,哪一種比較適合我們使用呢?下面腳本之家小編給大家介紹下python的格式化輸出(format,%)實例詳解,感興趣的朋友一起看看吧
    2018-06-06
  • Python中人臉圖像特征提取方法(HOG、Dlib、CNN)簡述

    Python中人臉圖像特征提取方法(HOG、Dlib、CNN)簡述

    這篇文章主要介紹了Python中人臉圖像特征提取方法(HOG、Dlib、CNN)簡述,需要的朋友可以參考下
    2021-08-08
  • python判斷文件是否存在,不存在就創(chuàng)建一個的實例

    python判斷文件是否存在,不存在就創(chuàng)建一個的實例

    今天小編就為大家分享一篇python判斷文件是否存在,不存在就創(chuàng)建一個的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-02-02
  • 使用python 和 lint 刪除項目無用資源的方法

    使用python 和 lint 刪除項目無用資源的方法

    這篇文章主要介紹了利用 python 和 lint 刪除項目無用資源的方法,使用方法是將 python 目錄下的 delUnused.py 放到項目目錄下,然后直接運行即可,需要的朋友可以參考下
    2017-12-12
  • 使用Python的time庫格式化時間的方法

    使用Python的time庫格式化時間的方法

    通過使用Python的time庫,我們可以方便地進行時間處理、格式化、解析和計算等操作,本文介紹了time庫的一些常見功能和使用方法,包括格式化時間、解析時間戳、獲取當(dāng)前時間、計算時間差等,感興趣的朋友一起看看吧
    2023-11-11
  • Python?中enum的使用方法總結(jié)

    Python?中enum的使用方法總結(jié)

    這篇文章主要介紹了Python?中enum的使用方法總結(jié),枚舉在許多編程語言中常被表示為一種基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)使用,下文更多詳細內(nèi)容需要的小伙伴可以參考一下
    2022-03-03

最新評論

安顺市| 兰西县| 广饶县| 凉山| 成安县| 鄂托克前旗| 乌兰浩特市| 永寿县| 洪洞县| 门头沟区| 甘孜| 巴中市| 卢湾区| 通州区| 乳源| 白玉县| 吴江市| 凤庆县| 故城县| 嘉禾县| 唐海县| 全椒县| 定结县| 铁力市| 丹巴县| 阳城县| 静安区| 濮阳市| 遂溪县| 阳泉市| 大余县| 汉源县| 当雄县| 延川县| 黑河市| 北安市| 宣城市| 莱芜市| 栾川县| 惠安县| 广水市|