萬盛學電腦網

 萬盛學電腦網 >> 網絡編程 >> 編程語言綜合 >> Python的Flask框架中實現簡單的登錄功能的教程

Python的Flask框架中實現簡單的登錄功能的教程

   Python的Flask框架中實現簡單的登錄功能的教程,登錄是各個web框架中的基礎功能,需要的朋友可以參考下

  回顧

  在前面的系列章節中,我們創建了一個數據庫並且學著用用戶和郵件來填充,但是到現在我們還沒能夠植入到我們的程序中。 兩章之前,我們已經看到怎麼去創建網絡表單並且留下了一個實現完全的登陸表單。

  在這篇文章中,我們將基於我門所學的網絡表單和數據庫來構建並實現我們自己的用戶登錄系統。教程的最後我們小程序會實現新用戶注冊,登陸和退出的功能。

  為了能跟上這章節,你需要前一章節最後部分,我們留下的微博程序。請確保你的程序已經正確安裝和運行。

  在前面的章節,我們開始配置我們將要用到的Flask擴展。為了登錄系統,我們將使用兩個擴展,Flask-Login 和 Flask-OpenID. 配置如下所示 (fileapp__init__.py):

  ?

1 2 3 4 5 6 7 8 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 擴展為了可以存儲臨時文件,需要一個臨時文件夾路徑。為此,我們提供了它的位置。

  重訪我們的用戶模型

  Flask-Login擴展需要在我們的User類裡實現一些方法。除了這些方法以外,類沒有被要求實現其它方法。

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

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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 '<User %r>' % (self.name)

  is_authenticated方法是一個誤導性的名字的方法,通常這個方法應該返回True,除非對象代表一個由於某種原因沒有被認證的用戶。

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

  is_anonymous方法應該為那些不被獲准登錄的用戶返回True。

  最後,get_id方法為用戶返回唯一的unicode標識符。我們用數據庫層生成唯一的id。

  用戶加載回調

  現在我們通過使用Flask-Login和Flask-OpenID擴展來實現登錄系統

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

  ?

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

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

  登錄視圖函數

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

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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'])

  注意到我們導入了一些新的模塊,其中有些後面會用到。

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

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

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

  我們在調用redirect()時使用的url_for()方法是Flask定義的從給定的view方法獲取url。如果你想重定向到index頁面,你h很可能使用redirect('/index'),但是我們有很好的理由讓Flask為你構造url。

  當我們從登錄表單得到返回數據,接下來要運行的代碼也是新寫的。這兒我們做兩件事。首先我們保存remember_me的布爾值到Flask的session中,別和Flask-SQLAlchemy的db.session混淆了。我們已經知道在一個request的生命周期中用Flask的g對象來保存和共享數據。沿著這條線路Flask的session提供了更多,更復雜的服務。一旦數據被保存到session中,它將在同一客戶端發起的這次請求和這次以後的請求中永存而不會消亡。數據將保持在session中直到被明確的移除。為了做到這些,Flask為每個客戶端建立各自的session。

  下面的oid.try_login是通過Flask-OpenID來執行用戶認證。這個方法有兩個參數,web表單提供的openid和OpenID provider提供的我們想要的list數據項。由於我們定義了包含nickname和email的User類,所以我們要從找nickname和email這些項。

  基於OpenID的認證是異步的。如果認證成功,Flask-OpenID將調用有由oid.after_login裝飾器注冊的方法。如果認證失敗那麼用戶會被重定向到login頁面。

  Flask-OpenID登錄回調

  這是我們實現的after_login方法(app/views.py)

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @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)
copyright © 萬盛學電腦網 all rights reserved