用 Flask 来写个轻博客 (23) — 应用 OAuth 来实现 Facebook 第三方登录
目录
前文列表
用 Flask 来写个轻博客 (1) — 创建项目
用 Flask 来写个轻博客 (2) — Hello World!
用 Flask 来写个轻博客 (3) — (M)VC_连接 MySQL 和 SQLAlchemy
用 Flask 来写个轻博客 (4) — (M)VC_创建数据模型和表
用 Flask 来写个轻博客 (5) — (M)VC_SQLAlchemy 的 CRUD 详解
用 Flask 来写个轻博客 (6) — (M)VC_models 的关系(one to many)
用 Flask 来写个轻博客 (7) — (M)VC_models 的关系(many to many)
用 Flask 来写个轻博客 (8) — (M)VC_Alembic 管理数据库结构的升级和降级
用 Flask 来写个轻博客 (9) — M(V)C_Jinja 语法基础快速概览
用 Flask 来写个轻博客 (10) — M(V)C_Jinja 常用过滤器与 Flask 特殊变量及方法
用 Flask 来写个轻博客 (11) — M(V)C_创建视图函数
用 Flask 来写个轻博客 (12) — M(V)C_编写和继承 Jinja 模板
用 Flask 来写个轻博客 (13) — M(V)C_WTForms 服务端表单检验
用 Flask 来写个轻博客 (14) — M(V)C_实现项目首页的模板
用 Flask 来写个轻博客 (15) — M(V)C_实现博文页面评论表单
用 Flask 来写个轻博客 (16) — MV(C)_Flask Blueprint 蓝图
用 Flask 来写个轻博客 (17) — MV(C)_应用蓝图来重构项目
用 Flask 来写个轻博客 (18) — 使用工厂模式来生成应用对象
用 Flask 来写个轻博客 (19) — 以 Bcrypt 密文存储账户信息与实现用户登陆表单
用 Flask 来写个轻博客 (20) — 实现注册表单与应用 reCAPTCHA 来实现验证码
用 Flask 来写个轻博客 (21) — 结合 reCAPTCHA 验证码实现用户注册与登录
用 Flask 来写个轻博客 (22) — 实现博客文章的添加和编辑页面
扩展阅读
第三方登录流程
Resource Owner:资源所有者,本文中又称”用户”(user)。
Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。
Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。
(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。
不难看出来,上面六个步骤之中,(B) 是整个流程的关键,有了这个授权以后,客户端就可以获取令牌,进而凭令牌获取资源。 那用户怎样才能给于客户端授权? 我们可以使用 OAuth 来实现.
OAuth
OAuth 的作用就是让”客户端(blog application)”安全可控地获取”服务商用户(Facebook User)”帐号的授权,与”服务商提供商(Facebook)”进行互动。
OAuth在”客户端”与”服务提供商”之间,设置了一个授权层(authorization layer)。”客户端”不能直接登录”服务提供商”,只能登录授权层,以此将用户与客户端分离。”客户端”登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。
“客户端”登录授权层以后,”服务提供商”根据令牌的权限范围和有效期,向”客户端”开放用户储存的资料。由此可见, 用户账户的安全性就交由这些知名的可靠的”服务提供商”来处理了, 可以更好的降低用户登录 blog 的信任成本.
应用 OAuth 实现 Facebook 第三方登录
- 安装
pip install Flask-OAuth
pip freeze > requirements.txt
到 facebook developer 上创建 facebook 并获取 app_id 和 app_Secret, 并注册授权站点, 这里我们使用 http://localhost:5000/
初始化 OAuth 对象, 并使用该对象来获取 facebook 对象
vim extensions.py
from flask_oauth import OAuth
# Create the Flask-OAuth's instance
oauth = OAuth()
# facebook 第三方登录接口
# Create the auth object for facebook.
facebook = oauth.remote_app(
'facebook',
base_url='https://graph.facebook.com/',
request_token_url=None,
access_token_url='/oauth/access_token',
authorize_url='https://www.facebook.com/dialog/oauth',
consumer_key='<Your_app_number>',
consumer_secret='<Your_app_secret>',
request_token_params={'scope': 'email'})
@facebook.tokengetter
def get_facebook_token():
return session.get('facebook_oauth_token')
NOTE 1: facebook 对象是上述步骤中创建的 facebook 应用对象, 其包含了认证的结果信息和请求授权的 facebook user 信息. facebook 是完成第三方登录流程的接口对象.
NOTE 2: 方法 get_facebook_oauth_token() 获取 facebook 发放的 token. 当成功创建 facebook 对象并完成授权时, 表示 client(blog) 成功的向 Authorization server 完成认证并接受到服务端的 token, 并保存在 session 中. 然后 Client 就可以使用这个 token 去访问 facebook 的资源(账户权限资源)了.
- 实现在 client 触发用户授权的逻辑
vim jmilkfansblog/controllers/main.py
from jmilkfansblog.extensions import openid, facebook
# 当访问 /facebook 时, 触发授权流程
main_blueprint.route('/facebook')
def facebook_login():
return facebook.authorize(
callback=url_for('main.facebook_authorized',
next=request.referrer or None,
_external=True))
# 该视图会接受从 facebook 认证服务器返回的 resp 对象, 可以通过 resp 对象来判断 Client 在 Server 上的认证结果.
@main_blueprint.route('/facebook/authorized')
@facebook.authorized_handler
def facebook_authorized(resp):
if resp is None:
return 'Access denied: reason=%s error=%s' % (
request.args['error_reason'],
request.args['error_description'])
session['facebook_oauth_token'] = (resp['access_token'], '')
me = facebook.get('/me')
if me.data.get('first_name', False):
facebook_username = me.data['first_name'] + " " + me.data['last_name']
else:
facebook_username = me.data['name']
user = User.query.filter_by(username=facebook_username).first()
if user is None:
user = User(id=str(uuid4()), username=facebook_username, password='jmilkfan')
db.session.add(user)
db.session.commit()
flash('You have been logged in.', category='success')
return redirect(url_for('blog.home'))
- 实现登录链接
<div class="row">
<div class="form-group">
<a href="{{ url_for('main.facebook_login') }}">Login via Facebook</a>
</div>
</div>
实现效果
访问 /faceboook/authorized 进入用户授权页面:
NOTE: 需要首先登录到 facebook 之后, 才能够进入授权的处理流程.
授权并登录成功:
用 Flask 来写个轻博客 (23) — 应用 OAuth 来实现 Facebook 第三方登录的更多相关文章
- 用 Flask 来写个轻博客 (21) — 结合 reCAPTCHA 验证码实现用户注册与登录
目录 目录 前文列表 扩展阅读 添加账户管理蓝图 新建控制器蓝图 新建表单 新建蓝图 main 的视图函数 新建模板 页面效果 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Fla ...
- 用 Flask 来写个轻博客
用 Flask 来写个轻博客 用 Flask 来写个轻博客 (1) — 创建项目 用 Flask 来写个轻博客 (2) — Hello World! 用 Flask 来写个轻博客 (3) — (M)V ...
- 用 Flask 来写个轻博客 (37) — 在 Github 上为第一阶段的版本打 Tag
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 第一阶段结语 打 Tag 前文列表 用 Flask 来写个轻博客 (1 ...
- 用 Flask 来写个轻博客 (36) — 使用 Flask-RESTful 来构建 RESTful API 之五
目录 目录 前文列表 PUT 请求 DELETE 请求 测试 对一条已经存在的 posts 记录进行 update 操作 删除一条记录 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 ...
- 用 Flask 来写个轻博客 (35) — 使用 Flask-RESTful 来构建 RESTful API 之四
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 POST 请求 身份认证 测试 前文列表 用 Flask 来写个轻博客 ...
- 用 Flask 来写个轻博客 (34) — 使用 Flask-RESTful 来构建 RESTful API 之三
目录 目录 前文列表 应用请求中的参数实现 API 分页 测试 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask 来写个轻博客 (2) - Hello World! 用 F ...
- 用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 构建 RESTful Flask API 定义资源路由 格式 ...
- 用 Flask 来写个轻博客 (32) — 使用 Flask-RESTful 来构建 RESTful API 之一
目录 目录 前文列表 扩展阅读 RESTful API REST 原则 无状态原则 面向资源 RESTful API 的优势 REST 约束 前文列表 用 Flask 来写个轻博客 (1) - 创建项 ...
- 用 Flask 来写个轻博客 (31) — 使用 Flask-Admin 实现 FileSystem 管理
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 编写 FileSystem Admin 页面 Flask-A ...
随机推荐
- Jmeter录制web和app脚本
前置: 一.已经安装了jmeter 步骤: 一.打开jmeter,右键测试计划-->添加添加线程组-->线程-->线程组,新建线程组 二.右键线程组-->添加-->逻辑控 ...
- python学习第二十二天文件byte类型
所有的文件在计算机里面存储为二进制形式,但是我们有时候有需要将二进制转换为gbk或者utf-8形式,编码的时候encode 解码的时候decode ,下面简单阐述python二进制在文件传输过程的作用 ...
- 返回与Table结构相同的DataTable副本
/// <summary> /// 返回与Table结构相同的DataTable副本 /// </summary> public static DataTable getStr ...
- spring(五):spring中Aware接口的使用
spring中自定义组件需要使用spring的底层组件时,可以通过自定义组件实现相关XxxAware接口,重写其中的方法进而实现 例如:自定义一个组件,该组件中需要使用ApplicationConte ...
- 上传.cgi在252板子上跑
1.windows下写好.c程序 2.进入linux,准备交叉编译 arm-hisiv600-linux-gcc -g -Wall -o xxx.cgi xxx.c(交叉编译工具取决于板子) 3.把. ...
- elasticsearch 基础 —— URI搜索
URI搜索 可以通过提供请求参数使用URI来执行搜索请求.使用此模式执行搜索时,并非所有搜索选项都会暴露.这是一个例子: GET twitter/_search?q=user:kimchy 示例响应: ...
- NHibernet 事务 修改操作,事务没提交,数据库数据却同步(修改)了
Nhibernet 缓存 由于查询出来的数据和缓存关联,更新之后就算事务没执行提交操作,数据库依旧会更新,解决方法, 清空缓存,实例不和缓存关联,如下面标红代码 public bool UpdateT ...
- 《YC创业营:硅谷顶级创业孵化器如何改变世界》:YC2011批量天使投资记录 三星推荐
这个YC创业营是一个硅谷的天使投资基金,每年两次批量投资创业公司.本书说的是2011年YC批量选择了64个创业团队,让他们集中到硅谷办公3个月,给他们创业指导,帮他们找A轮投资. YC创始人偏爱25岁 ...
- Jade To Pug过程中的一个小问题
最近在使用jade+express+typescript搭建一个博客项目,在使用jade-bootstrap项目时出现了一个问题 在使用其中的carousel时,发现其中的变量并没有转义 +carou ...
- ubuntu在线搭建ftp服务器
转载:https://www.linuxidc.com/Linux/2016-12/138563.htm 在Linux中ftp服务器的全名叫 vsftpd,我们需要利用相关命令来开启安装ftp服务器, ...