日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
創(chuàng)新互聯(lián)Python教程:flask如何驗證登錄

用戶認證的原理

10年積累的網(wǎng)站設(shè)計制作、成都網(wǎng)站制作經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認識你,你也不認識我。但先做網(wǎng)站后付款的網(wǎng)站建設(shè)流程,更有平昌免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

在了解使用Flask來實現(xiàn)用戶認證之前,我們首先要明白用戶認證的原理。假設(shè)現(xiàn)在我們要自己去實現(xiàn)用戶認證,需要做哪些事情呢?

首先,用戶要能夠輸入用戶名和密碼,所以需要網(wǎng)頁和表單,用以實現(xiàn)用戶輸入和提交的過程。

用戶提交了用戶名和密碼,我們就需要比對用戶名,密碼是否正確,而要想比對,首先我們的系統(tǒng)中就要有存儲用戶名,密碼的地方,大多數(shù)后臺系統(tǒng)會通過數(shù)據(jù)庫來存儲,但是實際上我們也可以簡單的存儲到文件當中。

登錄之后,我們需要維持用戶登錄狀態(tài),以便用戶在訪問特定網(wǎng)頁的時候來判斷用戶是否已經(jīng)登錄,以及是否有權(quán)限訪問改網(wǎng)頁。這就需要有維護一個會話來保存用戶的登錄狀態(tài)和用戶信息。

從第三步我們也可以看出,如果我們的網(wǎng)頁需要權(quán)限保護,那么當請求到來的時候,我們就首先要檢查用戶的信息,比如是否已經(jīng)登錄,是否有權(quán)限等,如果檢查通過,那么在response的時候就會將相應(yīng)網(wǎng)頁回復給請求的用戶,但是如果檢查不通過,那么就需要返回錯誤信息。

在第二步,我們知道要將用戶名和密碼存儲起來,但是如果只是簡單的用明文存儲用戶名和密碼,很容易被“有心人”盜取,從而造成用戶信息泄露,那么我們實際上應(yīng)當將用戶信息尤其是密碼做加密處理之后再存儲比較安全。

用戶登錄

通過Flask以及相應(yīng)的插件來實現(xiàn)登錄過程

接下來講述如何通過Flask框架以及相應(yīng)的插件來實現(xiàn)整個登錄過程,需要用到的插件如下:

flask-wtf

wtf

werkzeug

flask_login

使用flask-wtf和wtf來實現(xiàn)表單功能

flask-wtf對wtf做了一些封裝,不過有些東西還是要直接用wtf,比如StringField等。flask-wtf和wtf主要是用于建立html中的元素和Python中的類的對應(yīng)關(guān)系,通過在Python代碼中操作對應(yīng)的類,對象等從而控制html中的元素。我們需要在python代碼中使用flask-wtf和wtf來定義前端頁面的表單(實際是定義一個表單類),再將對應(yīng)的表單對象作為render_template函數(shù)的參數(shù),傳遞給相應(yīng)的template,之后Jinja模板引擎會將相應(yīng)的template渲染成html文本,再作為http response返回給用戶。

定義表單類示例代碼:

from flask_wtf import FlaskForm
from wtforms import StringField, BooleanField, PasswordField
from wtforms.validators import DataRequired
# 定義的表單都需要繼承自FlaskForm
class LoginForm(FlaskForm):
    # 域初始化時,第一個參數(shù)是設(shè)置label屬性的
    username = StringField('User Name', validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    remember_me = BooleanField('remember me', default=False)

在wtf當中,每個域代表就是html中的元素,比如StringField代表的是元素,當然wtf的域還定義了一些特定功能,比如validators,可以通過validators來對這個域的數(shù)據(jù)做檢查,詳細請參考wtf教程。
對應(yīng)的html模板可能如下login.html:

{% extends "layout.html" %}


Login Page



User Name:

Password:

Remember Me

{{ form.csrf_token }}

這里{{ form.csrf_token }}也可以使用{{ form.hidden_tag() }}來替換

同時我們也可以使用form去定義模板,跟直接用html標簽去定義效果是相同的,Jinja模板引擎會將對象、屬性轉(zhuǎn)化為對應(yīng)的html標簽,
相對應(yīng)的template,如下login.html:

{% extends "base.html" %}
{% block content %}

Sign In

{{ form.csrf_token }}

{{ form.username.label }}
{{ form.username(size=80) }}

{{ form.password.label }}
{{ form.password(size=80) }}

{{ form.remember_me }} Remember Me

{% endblock %}

現(xiàn)在我們需要在view中定義相應(yīng)的路由,并將相應(yīng)的登錄界面展示給用戶。
簡單起見,將view的相關(guān)路由定義放在主程序當中

@app.route('/login')
def login():
    form = LoginForm()
    return render_template('login.html', title="Sign In", form=form)

這里簡單起見,當用戶請求'/login'路由時,直接返回login.html網(wǎng)頁,注意這里的html網(wǎng)頁是經(jīng)過Jinja模板引擎將相應(yīng)的模板轉(zhuǎn)換后的html網(wǎng)頁。

至此,如果我們把以上代碼整合到flask當中,就應(yīng)該能夠看到相應(yīng)的登錄界面了,那么當用戶提交之后,我們應(yīng)當怎樣存儲呢?這里我們暫時先不用數(shù)據(jù)庫這樣復雜的工具存儲,先簡單地存為文件。接下來就看下如何去存儲。

加密和存儲

我們可以首先定義一個User類,用于處理與用戶相關(guān)的操作,包括存儲和驗證等。

from werkzeug.security import generate_password_hash
from werkzeug.security import check_password_hash
from flask_login import UserMixin
import json
import uuid
# define profile.json constant, the file is used to
# save user name and password_hash
PROFILE_FILE = "profiles.json"
class User(UserMixin):
def __init__(self, username):
self.username = username
self.id = self.get_id()
    @property
def password(self):
raise AttributeError('password is not a readable attribute')
    @password.setter
def password(self, password):
"""save user name, id and password hash to json file"""
self.password_hash = generate_password_hash(password)
with open(PROFILE_FILE, 'w+') as f:
try:
profiles = json.load(f)
except ValueError:
profiles = {}
profiles[self.username] = [self.password_hash,
self.id]
f.write(json.dumps(profiles))
def verify_password(self, password):
password_hash = self.get_password_hash()
if password_hash is None:
return False
return check_password_hash(self.password_hash, password)
def get_password_hash(self):
"""try to get password hash from file.
        :return password_hash: if the there is corresponding user in
                the file, return password hash.
                None: if there is no corresponding user, return None.
        """
try:
with open(PROFILE_FILE) as f:
user_profiles = json.load(f)
user_info = user_profiles.get(self.username, None)
if user_info is not None:
return user_info[0]
except IOError:
return None
except ValueError:
return None
return None
def get_id(self):
"""get user id from profile file, if not exist, it will
        generate a uuid for the user.
        """
if self.username is not None:
try:
with open(PROFILE_FILE) as f:
user_profiles = json.load(f)
if self.username in user_profiles:
return user_profiles[self.username][1]
except IOError:
pass
except ValueError:
pass
return unicode(uuid.uuid4())
    @staticmethod
def get(user_id):
"""try to return user_id corresponding User object.
        This method is used by load_user callback function
        """
if not user_id:
return None
try:
with open(PROFILE_FILE) as f:
user_profiles = json.load(f)
for user_name, profile in user_profiles.iteritems():
if profile[1] == user_id:
return User(user_name)
except:
return None
return None

User類需要繼承flask-login中的UserMixin類,用于實現(xiàn)相應(yīng)的用戶會話管理。這里我們是直接存儲用戶信息到一個json文件"profiles.json"我們并不直接存儲密碼,而是存儲加密后的hash值,在這里我們使用了werkzeug.security包中的generate_password_hash函數(shù)來進行加密,由于此函數(shù)默認使用了sha1算法,并添加了長度為8的鹽值,所以還是相當安全的。一般用途的話也就夠用了。驗證password的時候,我們需要使用werkzeug.security包中的check_password_hash函數(shù)來驗證密碼get_id是UserMixin類中就有的method,在這我們需要overwrite這個method。在json文件中沒有對應(yīng)的user id時,可以使用uuid.uuid4()生成一個用戶唯一id。


名稱欄目:創(chuàng)新互聯(lián)Python教程:flask如何驗證登錄
文章地址:http://www.dlmjj.cn/article/cdpiiic.html