1、Python的Flask框架中实现简洁的登录功能的教程Python的Flask框架中实现简洁的登录功能的教程_ Python的Flask框架中实现简洁的登录功能的教程,登录是各个web框架中的基础功能,需要的伴侣可以参考下 回顾 在前面的系列章节中,我们创建了一个数据库并且学着用用户和邮件来填充,但是到现在我们还没能够植入到我们的程序中。 两章之前,我们已经看到怎么去创建网络表单并且留下了一个实现完全的登陆表单。 在这篇文章中,我们将基于我门所学的网络表单和数据库来构建并实现我们自己的用户登录系统。教程的最终我们小程序会实现新用户注册,登陆和退出的功能。 为了能跟上这章节,你需要前一章节最终部
2、分,我们留下的微博程序。请确保你的程序已经正确安装和运行。 在前面的章节,我们开头配置我们将要用到的Flask扩展。为了登录系统,我们将用法两个扩展,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
3、.path.join(basedir, tmp) Flask-OpenID 扩展为了可以存储临时文件,需要一个临时文件夹路径。为此,我们供应了它的位置。 重访我们的用户模型 Flask-Login扩展需要在我们的User类里实现一些方法。除了这些方法以外,类没有被要求实现其它方法。 下面是我们的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
4、 = db.Column(db.String(120), unique = True) role = db.Column(db.SmallInteger, default = ROLE_USER) = 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(
5、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扩展来实现登录系统
6、 首先,我们需要写一个方法从数据库加载到一个用户。这个方法会被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时,有必要把它转化成integer类型。 登录视图函数 接下来我们要更新登录视图函数(fileapp/views.py): from flask import render_template, flash, redir
7、ect, 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.use
8、r is not None and g.user.is_authenticated(): return redirect(url_for(index) form = LoginForm() if form.validate_on_submit(): sessionremember_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, p
9、roviders = app.configOPENID_PROVIDERS) 留意到我们导入了一些新的模块,其中有些后面会用到。 跟上个版本的改变很小。我们给视图函数添加了一个新的装饰器:oid.loginhandler。它告诉Flask-OpenID这是我们的登录视图函数。 在方法体的开头,我们检测是是否用户是已经经过登录认证的,假如是就重定向到index页面。这儿的思路是假如一个用户已经登录了,那么我们不会让它做二次登录。 全局变量g是Flask设置的,在一个request生命周期中,用来存储和共享数据的变量。所以我猜你已经想到了,我们将把已经登录的用户放到g变量里。 我们在调用redir
10、ect()时用法的url_for()方法是Flask定义的从给定的view方法猎取url。假如你想重定向到index页面,你h很可能用法redirect(/index),但是我们有很好的理由让Flask为你构造url。 当我们从登录表单得到返回数据,接下来要运行的代码也是新写的。这儿我们做两件事。首先我们保存remember_me的布尔值到Flask的session中,别和Flask-SQLAlchemy的db.session混淆了。我们已经知道在一个request的生命周期中用Flask的g对象来保存和共享数据。沿着这条线路Flask的session供应了更多,更简单的服务。一旦数据被保存到
11、session中,它将在同一客户端发起的这次恳求和这次以后的恳求中永存而不会消亡。数据将保持在session中直到被明确的移除。为了做到这些,Flask为每个客户端建立各自的session。 下面的oid.try_login是通过Flask-OpenID来执行用户认证。这个方法有两个参数,web表单供应的openid和OpenID provider供应的我们想要的list数据项。由于我们定义了包含nickname和email的User类,所以我们要从找nickname和email这些项。 基于OpenID的认证是异步的。假如认证胜利,Flask-OpenID将调用有由oid.after_log
12、in装饰器注册的方法。假如认证失败那么用户会被重定向到login页面。 Flask-OpenID登录回调 这是我们实现的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 No
13、ne: nickname = resp.nickname if nickname is None or nickname = : nickname = resp.email.split( user = User(nickname = nickname, email = resp.email, role = ROLE_USER) db.session.add(user) mit() remember_me = False if remember_me in session: remember_me = sessionremember_me session.pop(remember_me, Non
14、e) login_user(user, remember = remember_me) return redirect(request.args.get(next) or url_for(index) 传给after_login方法的resp参数包含了OpenID provider返回的一些信息。 第一个if声明仅仅是为了验证。我们要求一个有效的email,所以一个没有没供应的email我们是没法让他登录的。 接下来,我们将依据email查找数据库。假如email没有被找到我们就认为这是一个新的用户,所以我们将在数据库中增加一个新用户,做法就像我们从之前章节学到的一样。留意我们没有处理nick
15、name,由于一些OpenID provider并没有包含这个信息。 做完这些我们将从Flask session中猎取remember_me的值,假如它存在,那它是我们之前在login view方法中保存到session中的boolean类型的值。 然后我们调用Flask-Login的login_user方法,来注册这个有效的登录。 最终,在最终一行我们重定向到下一个页面,或者假如在request恳求中没有供应下个页面时,我们将重定向到index页面。 跳转到下一页的这个概念很简洁。比方说我们需要你登录才能导航到一个页面,但你现在并未登录。在Flask-Login中你可以通过login_req
16、uired装饰器来限定未登录用户。假如一个用户想连接到一个限定的url,那么他将被自动的重定向到login页面。Flask-Login将保存最初的url作为下一个页面,一旦登录完成我们便跳转到这个页面。 做这个工作Flask-Login需要知道用户当前在那个页面。我们可以在app的初始化组件里配置它(app/_init_.py): lm = LoginManager() lm.setup_app(app) lm.login_view = login 全局变量g.user 假如你留意力很集中,那么你应当记得在login view方法中我们通过检查g.user来推断一个用户是否登录了。为了实现这个
17、我们将用法Flask供应的before_request大事。任何一个被before_request装饰器装饰的方法将会在每次request恳求被收到时提前与view方法执行。所以在这儿来设置我们的g.user变量(app/views.py): app.before_request def before_request(): g.user = current_user 这就是它要做的一切,current_user全局变量是被Flask-Login设定的,所以我们只需要把它拷贝到更简单被访问的g变量就OK了。这样,全部的恳求都能访问这个登录的用户,甚至于内部的模板。 index视图 在之前的章节中
18、我们用假代码遗留了我们的index视图,由于那个时候我们系统里并没有用户和博客文章。现在我们有用户了,所以,让我们来完成它吧: app.route(/) app.route(/index) login_required def index(): user = g.user = author: nickname: John , body: Beautiful day in Portland! , author: nickname: Susan , body: The Avengers movie was so cool! return render_template(index.html, ti
19、tle = Home, user = user, = ) 在这个方法中只有两处变动。首先,我们增加了login_required装饰器。这样表明白这个页面只有登录用户才能访问。 另一个改动是把g.user传给了模板,替换了之间的假对象。 现在可以运行我们的应用了。 当我们连接到你将会看到登陆页面。记着假如你通过OpenID登录那么你必需用法你的供应者供应的OpenID URL。你可以下面URL中的任何一个OpenID provider来为你产生一个正确的URL。 作为登录进程的一部分,你将会被重定向到OpenID供应商的网站,你将在那儿认证和授权你共享给我们应用的一些信息(我们只需要email
20、和nickname,放心,不会有任何密码或者其他个人信息被曝光)。 一旦登录完成你将作为已登录用户被带到index页面。 试试勾选remember_me复选框。有了这个选项当你在扫瞄器关闭应用后重新打开时,你还是已登录状态。 注销登录 我们已经实现了登录,现在是时候来实现注销登录了。 注销登录的方法灰常简洁(file app/views.py): app.route(/logout) def logout(): logout_user() return redirect(url_for(index) 但我们在模板中还没有注销登录的链接。我们将在base.html中的顶部导航栏添加这个链接(fi
21、le app/templates/base.html): html head % if title % titletitle - microblog/title % else % titlemicroblog/title % endif % /head body divMicroblog: a href= url_for(index) Home/a % if g.user.is_authenticated() % | a href= url_for(logout) Logout/a % endif % /div hr % with messages = get_flashed_messages() % % if messages % ul % for message in messages % li message /li % endfor % /ul % endif % % endwith % % block content % endblock % /body /html 这是多么多么简洁啊,我们只需要检查一下g.user中是否有一个有效的用户,假如有我们就添加注销链接。在我们的模板中我们再一次用法了url_for方法。 更多信息请查看IT技术专栏 .
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1