欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Python的Flask框架中實(shí)現(xiàn)簡單的登錄功能的教程

系統(tǒng) 1683 0

?回顧

在前面的系列章節(jié)中,我們創(chuàng)建了一個數(shù)據(jù)庫并且學(xué)著用用戶和郵件來填充,但是到現(xiàn)在我們還沒能夠植入到我們的程序中。 兩章之前,我們已經(jīng)看到怎么去創(chuàng)建網(wǎng)絡(luò)表單并且留下了一個實(shí)現(xiàn)完全的登陸表單。

在這篇文章中,我們將基于我門所學(xué)的網(wǎng)絡(luò)表單和數(shù)據(jù)庫來構(gòu)建并實(shí)現(xiàn)我們自己的用戶登錄系統(tǒng)。教程的最后我們小程序會實(shí)現(xiàn)新用戶注冊,登陸和退出的功能。

為了能跟上這章節(jié),你需要前一章節(jié)最后部分,我們留下的微博程序。請確保你的程序已經(jīng)正確安裝和運(yùn)行。


在前面的章節(jié),我們開始配置我們將要用到的Flask擴(kuò)展。為了登錄系統(tǒng),我們將使用兩個擴(kuò)展,Flask-Login 和 Flask-OpenID. 配置如下所示 (fileapp\__init__.py):
?

            
import os
from flaskext.login import LoginManager
from flaskext.openid import OpenID
from config import basedir
 
lm = LoginManager()
lm.setup_app(app)
oid = OpenID(app, os.path.join(basedir, 'tmp'))

          

Flask-OpenID 擴(kuò)展為了可以存儲臨時文件,需要一個臨時文件夾路徑。為此,我們提供了它的位置。


重訪我們的用戶模型

Flask-Login擴(kuò)展需要在我們的User類里實(shí)現(xiàn)一些方法。除了這些方法以外,類沒有被要求實(shí)現(xiàn)其它方法。

下面是我們的User類 (fileapp/models.py):
?

            
class User(db.Model):
 id = db.Column(db.Integer, primary_key = True)
 nickname = db.Column(db.String(64), unique = True)
 email = db.Column(db.String(120), unique = True)
 role = db.Column(db.SmallInteger, default = ROLE_USER)
 posts = db.relationship('Post', backref = 'author', lazy = 'dynamic')
 
 def is_authenticated(self):
  return True
 
 def is_active(self):
  return True
 
 def is_anonymous(self):
  return False
 
 def get_id(self):
  return unicode(self.id)
 
 def __repr__(self):
  return '
            
              ' % (self.name)

            
          

is_authenticated方法是一個誤導(dǎo)性的名字的方法,通常這個方法應(yīng)該返回True,除非對象代表一個由于某種原因沒有被認(rèn)證的用戶。

is_active方法應(yīng)該為用戶返回True除非用戶不是激活的,例如,他們已經(jīng)被禁了。

is_anonymous方法應(yīng)該為那些不被獲準(zhǔn)登錄的用戶返回True。

最后,get_id方法為用戶返回唯一的unicode標(biāo)識符。我們用數(shù)據(jù)庫層生成唯一的id。
?

用戶加載回調(diào)

現(xiàn)在我們通過使用Flask-Login和Flask-OpenID擴(kuò)展來實(shí)現(xiàn)登錄系統(tǒng)

首先,我們需要寫一個方法從數(shù)據(jù)庫加載到一個用戶。這個方法會被Flask-Login使用(fileapp/views.py):
?

            
@lm.user_loader
def load_user(id):
 return User.query.get(int(id))

          

記住Flask-Login里的user id一直是unicode類型的,所以在我們把id傳遞給Flask-SQLAlchemy時,有必要把它轉(zhuǎn)化成integer類型。

登錄視圖函數(shù)

接下來我們要更新登錄視圖函數(shù)(fileapp/views.py):
?

            
from flask import render_template, flash, redirect, session, url_for, request, g
from flaskext.login import login_user, logout_user, current_user, login_required
from app import app, db, lm, oid
from forms import LoginForm
from models import User, ROLE_USER, ROLE_ADMIN
 
@app.route('/login', methods = ['GET', 'POST'])
@oid.loginhandler
def login():
 if g.user is not None and g.user.is_authenticated():
  return redirect(url_for('index'))
 form = LoginForm()
 if form.validate_on_submit():
  session['remember_me'] = form.remember_me.data
  return oid.try_login(form.openid.data, ask_for = ['nickname', 'email'])
 return render_template('login.html',
  title = 'Sign In',
  form = form,
  providers = app.config['OPENID_PROVIDERS'])

          

注意到我們導(dǎo)入了一些新的模塊,其中有些后面會用到。

跟上個版本的變化很小。我們給視圖函數(shù)添加了一個新的裝飾器:oid.loginhandler。它告訴Flask-OpenID這是我們的登錄視圖函數(shù)。
?

在方法體的開頭,我們檢測是是否用戶是已經(jīng)經(jīng)過登錄認(rèn)證的,如果是就重定向到index頁面。這兒的思路是如果一個用戶已經(jīng)登錄了,那么我們不會讓它做二次登錄。

全局變量g是Flask設(shè)置的,在一個request生命周期中,用來存儲和共享數(shù)據(jù)的變量。所以我猜你已經(jīng)想到了,我們將把已經(jīng)登錄的用戶放到g變量里。

我們在調(diào)用redirect()時使用的url_for()方法是Flask定義的從給定的view方法獲取url。如果你想重定向到index頁面,你h很可能使用redirect('/index'),但是我們有很好的理由讓Flask為你構(gòu)造url。
?
當(dāng)我們從登錄表單得到返回數(shù)據(jù),接下來要運(yùn)行的代碼也是新寫的。這兒我們做兩件事。首先我們保存remember_me的布爾值到Flask的session中,別和Flask-SQLAlchemy的db.session混淆了。我們已經(jīng)知道在一個request的生命周期中用Flask的g對象來保存和共享數(shù)據(jù)。沿著這條線路Flask的session提供了更多,更復(fù)雜的服務(wù)。一旦數(shù)據(jù)被保存到session中,它將在同一客戶端發(fā)起的這次請求和這次以后的請求中永存而不會消亡。數(shù)據(jù)將保持在session中直到被明確的移除。為了做到這些,F(xiàn)lask為每個客戶端建立各自的session。

下面的oid.try_login是通過Flask-OpenID來執(zhí)行用戶認(rèn)證。這個方法有兩個參數(shù),web表單提供的openid和OpenID provider提供的我們想要的list數(shù)據(jù)項(xiàng)。由于我們定義了包含nickname和email的User類,所以我們要從找nickname和email這些項(xiàng)。

基于OpenID的認(rèn)證是異步的。如果認(rèn)證成功,F(xiàn)lask-OpenID將調(diào)用有由oid.after_login裝飾器注冊的方法。如果認(rèn)證失敗那么用戶會被重定向到login頁面。

Flask-OpenID登錄回調(diào)

這是我們實(shí)現(xiàn)的after_login方法(app/views.py)
?

            
@oid.after_login
def after_login(resp):
 if resp.email is None or resp.email == "":
  flash('Invalid login. Please try again.')
  redirect(url_for('login'))
 user = User.query.filter_by(email = resp.email).first()
 if user is None:
  nickname = resp.nickname
  if nickname is None or nickname == "":
   nickname = resp.email.split('@')[0]
  user = User(nickname = nickname, email = resp.email, role = ROLE_USER)
  db.session.add(user)
  db.session.commit()
 remember_me = False
 if 'remember_me' in session:
  remember_me = session['remember_me']
  session.pop('remember_me', None)
 login_user(user, remember = remember_me)
 return redirect(request.args.get('next') or url_for('index'))

          

傳給after_login方法的resp參數(shù)包含了OpenID provider返回的一些信息。

第一個if聲明僅僅是為了驗(yàn)證。我們要求一個有效的email,所以一個沒有沒提供的email我們是沒法讓他登錄的。


接下來,我們將根據(jù)email查找數(shù)據(jù)庫。如果email沒有被找到我們就認(rèn)為這是一個新的用戶,所以我們將在數(shù)據(jù)庫中增加一個新用戶,做法就像我們從之前章節(jié)學(xué)到的一樣。注意我們沒有處理nickname,因?yàn)橐恍㎡penID provider并沒有包含這個信息。

做完這些我們將從Flask session中獲取remember_me的值,如果它存在,那它是我們之前在login view方法中保存到session中的boolean類型的值。

然后我們調(diào)用Flask-Login的login_user方法,來注冊這個有效的登錄。


最后,在最后一行我們重定向到下一個頁面,或者如果在request請求中沒有提供下個頁面時,我們將重定向到index頁面。

跳轉(zhuǎn)到下一頁的這個概念很簡單。比方說我們需要你登錄才能導(dǎo)航到一個頁面,但你現(xiàn)在并未登錄。在Flask-Login中你可以通過login_required裝飾器來限定未登錄用戶。如果一個用戶想連接到一個限定的url,那么他將被自動的重定向到login頁面。Flask-Login將保存最初的url作為下一個頁面,一旦登錄完成我們便跳轉(zhuǎn)到這個頁面。

做這個工作Flask-Login需要知道用戶當(dāng)前在那個頁面。我們可以在app的初始化組件里配置它(app/__init__.py):
?

            
lm = LoginManager()
lm.setup_app(app)
lm.login_view = 'login'

          

全局變量g.user

如果你注意力很集中,那么你應(yīng)該記得在login view方法中我們通過檢查g.user來判斷一個用戶是否登錄了。為了實(shí)現(xiàn)這個我們將使用Flask提供的before_request事件。任何一個被before_request裝飾器裝飾的方法將會在每次request請求被收到時提前與view方法執(zhí)行。所以在這兒來設(shè)置我們的g.user變量(app/views.py):
?

            
@app.before_request
def before_request():
 g.user = current_user

          

這就是它要做的一切,current_user全局變量是被Flask-Login設(shè)定的,所以我們只需要把它拷貝到更容易被訪問的g變量就OK了。這樣,所有的請求都能訪問這個登錄的用戶,甚至于內(nèi)部的模板。

index視圖

在之前的章節(jié)中我們用假代碼遺留了我們的index視圖,因?yàn)槟莻€時候我們系統(tǒng)里并沒有用戶和博客文章。現(xiàn)在我們有用戶了,所以,讓我們來完成它吧:
?

            
@app.route('/')
@app.route('/index')
@login_required
def index():
 user = g.user
 posts = [
  {
   'author': { 'nickname': 'John' },
   'body': 'Beautiful day in Portland!'
  },
  {
   'author': { 'nickname': 'Susan' },
   'body': 'The Avengers movie was so cool!'
  }
 ]
 return render_template('index.html',
  title = 'Home',
  user = user,
  posts = posts)

          

在這個方法中只有兩處變動。首先,我們增加了login_required裝飾器。這樣表明了這個頁面只有登錄用戶才能訪問。

另一個改動是把g.user傳給了模板,替換了之間的假對象。


現(xiàn)在可以運(yùn)行我們的應(yīng)用了。

當(dāng)我們連接到http://localhost:5000你將會看到登陸頁面。記著如果你通過OpenID登錄那么你必須使用你的提供者提供的OpenID URL。你可以下面URL中的任何一個OpenID provider來為你產(chǎn)生一個正確的URL。

作為登錄進(jìn)程的一部分,你將會被重定向到OpenID提供商的網(wǎng)站,你將在那兒認(rèn)證和授權(quán)你共享給我們應(yīng)用的一些信息(我們只需要email和nickname,放心,不會有任何密碼或者其他個人信息被曝光)。

一旦登錄完成你將作為已登錄用戶被帶到index頁面。

試試勾選remember_me復(fù)選框。有了這個選項(xiàng)當(dāng)你在瀏覽器關(guān)閉應(yīng)用后重新打開時,你還是已登錄狀態(tài)。

注銷登錄

我們已經(jīng)實(shí)現(xiàn)了登錄,現(xiàn)在是時候來實(shí)現(xiàn)注銷登錄了。

注銷登錄的方法灰常簡單(file app/views.py):
?

            
@app.route('/logout')
def logout():
 logout_user()
 return redirect(url_for('index'))

          

但我們在模板中還沒有注銷登錄的鏈接。我們將在base.html中的頂部導(dǎo)航欄添加這個鏈接(file app/templates/base.html):

?

            

 
 {% if title %}
 
            
              {{title}} - microblog
            
            
 {% else %}
 
            
              microblog
            
            
 {% endif %}
 
 
 
            
Microblog: Home {% if g.user.is_authenticated() %} | Logout {% endif %}

{% with messages = get_flashed_messages() %} {% if messages %}
    {% for message in messages %}
  • {{ message }}
  • {% endfor %}
{% endif %} {% endwith %} {% block content %}{% endblock %}

這是多么多么簡單啊,我們只需要檢查一下g.user中是否有一個有效的用戶,如果有我們就添加注銷鏈接。在我們的模板中我們再一次使用了url_for方法。

最后的話
我們現(xiàn)在有了一個全功能的用戶登錄系統(tǒng)。在下一章中,我們將創(chuàng)建用戶的個人資料頁,并顯示用戶的頭像。

在此期間,這里是更新的應(yīng)用程序代碼,包括在這篇文章中的所有變化:

下載 microblog-0.5.zip 。


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久riav国产精品 | 亚洲永久中文字幕在线 | 免费观看一级黄色片 | 精品亚洲一区二区三区四区五区 | 免费观看呢日本天堂视频 | 男女激情动态视频 | 521国产精品视频 | 图片综合区 | 一级片在线免费观看视频 | 日韩在线视频观看 | 亚洲在线播放视频 | 国产高清免费视频 | av午夜电影| 欧美精品一二区 | 国产专区欧美 | 国产精品成人免费观看 | 日韩视频观看 | 天天色官网 | 中文线码中文高清播放中 | 国产一区二区免费 | 黄色免费视频大全 | 午夜影院a | 白色白色视频免费观看 | 成年人在线观看视频 | 天天躁日日躁很很躁2022 | 日韩免费在线观看视频 | 五月天电影网 | 久久这里只有精品23 | 亚洲一区国产二区 | 欧美日韩一二三区 | 91sao国产在线观看 | A片扒开双腿猛进入免费观看 | 不卡中文一二三区 | 国产精品久久久久久久久免费 | 免费一区 | 波多野结衣免费线在线 | 亚洲黄色在线视频 | 狠狠干综合| 亚洲欧美国产一区二区三区 | 激情五月在线 | 一级黄色片毛片 |