hzyuhz 2020-06-03
by 太阳雪
上一次课程,我们了解了 OAuth 认证是怎么回事,以及了解了四种认证方式,今天我们将以 Github 为例,了解一下如何用 Flask 第三方应用
在之前的介绍 JWT 的时候,了解过 Authlib 库,Authlib 是集 JWT、OAuth1.0、OAuth2.0 于一身的终极 Python 认证框架,支持多种 Web 框架,例如 Django、requests、httpx,以及今天实践用的 Flask,还对 Django 和 Flask 做了专门的集成,让开发更简单
Github OAuth 应用时支持 OAuth2.0 协议的,用授权码的模式颁发
access_token
,即 授权码模式(authorization code)
首先需要去 github 上注册我们的应用,注册地址: https://github.com/settings/applications/new
从申请配置上可以看到,github 支持任意的域名,不需要做额外的认证和证明,这也是选择 github 做演示的原因,如果要用 微信 作为认证,需要申请开通开发者资质,比较麻烦,不过开发方式和都是类似的
申请成功后,可以看到自己创建的应用配置页面:
从上图红色框的位置,可以得到 client id
, 和 client secret
,必须妥善保管
注册成功第三方应用,就可以来开发客户端了
使用 pip 安装
pip install Authlib
如果一切正常,可以导入 Authlib 模板,例如,引入 jwt :
>>> from authlib.integrations.flask_client import OAuth >>>
创建一个 Flask 应用:
from flask import Flask, session, render_template, url_for, redirect from authlib.integrations.flask_client import OAuth app = Flask(__name__) app.secret_key = ‘!secret‘ oauth = OAuth(app)
secret_key
, 用于做跳转认证页的校验,是必须的,如果缺失,引导认证页会失败客户端需要做的是引导用户到认证页面,并且能能向认证服务器请求 access_token, OAuth 实例可以从应用的配置中读取
为了简便,将配置一同写入代码中,实际项目中建议使用单独的配置文件(后面 Flask 项目工程中会详细说明):
app.config["GITHUB_CLIENT_ID"] = ‘55ffa..<省略>...9e1fb3a‘ app.config["GITHUB_CLIENT_SECRET"] = ‘692317a38d0..<省略>...d63f2d9f8c‘ app.config["GITHUB_AUTHORIZE_URL"] = ‘https://github.com/login/oauth/authorize‘ app.config["GITHUB_AUTHORIZE_PARAMS"] = { ‘scope‘: ‘user repo‘ } app.config["GITHUB_ACCESS_TOKEN_URL"] = ‘https://github.com/login/oauth/access_token‘ app.config["GITHUB_API_BASE_URL"] = ‘https://api.github.com‘
GITHUB
_CLIENT_ID
、_CLIENT_SECRET
:注册应用成功后,由认证服务器提供_AUTHORIZE_URL
:用户认证页面 URL,会在认证服务器文档中找到_AUTHORIZE_PARAMS
:认证时提供的额外参数,通常用于指定授权范围,具体范围和格式参考认证服务器文档_ACCESS_TOKEN_URL
:获取 access_token
的 URL_API_BASE_URL
:资源服务器 api 根路径,具体查看资源服务器 api 文档完成配置后,创建认证服务器实例
:
github = oauth.register(‘github‘)
register
方法会根据配置创建认证服务器实例,参数同配置中的前缀,大小写随意认证服务器的实例
,也可以用 oauth.github
方式来获取认证服务器实例
@app.route(‘/login‘) def login(): redirect_uri = url_for(‘auth‘, _external=True) return github.authorize_redirect(redirect_uri)
url_for
函数得到 auth
视图函数的绝对访问路径,参数 _external
为 True
返回绝对路径authorize_redirect
方法接收一个 URL 作为参数,即获得授权后的回调地址。注意:跳转地址必须和注册时的完全一致authorize_redirect
方法会合成带参数的认证页 URL,并跳转过去@app.route(‘/auth/redirect‘) def auth(): token = github.authorize_access_token() user = github.get(‘user‘).json() """ 可以在此保存 token 和 用户信息,例如存入数据库 """ session[‘user‘] = user return redirect(‘/‘)
/
结尾,能同时兼容不以 /
结尾请求,但是这里需要与注册时的保持一致,否则可能无法跳转到认证页authorize_access_token
方法用于从认证服务器获取 access_token
,分装了交互细节get
方法用户获取用户的授权资源。参数为资源服务器 api 的名称,例如user
、user/repos
session
, 以便下次访问时获得实际应用中,可以在第一次获取用户信息后,引导用户用手机号或者邮箱注册,以便之后登录
@app.route(‘/‘) def homepage(): user = session.get(‘user‘) return render_template(‘home.html‘, user=user)
session
中获得 user
对象,将其内容显示在页面上,如果 user
为空,则显示登录连接home.html
是模板,具体内容参考示例代码@app.route(‘/logout‘) def logout(): session.pop(‘user‘, None) return redirect(‘/‘)
access_token
有效,客户端就可以从资源服务器上获取用户的信息或资源user
从 session
中删掉,跳转到首页github OAuth app 的
access_token
是长期的,不需要更新,这里用 Authlib 文档中的例子作为演示
OAuth2.0 协议中的 access_token
可以设置有效期,过期后需要用 refresh_token
重新获取
Authlib 提供了基于信号
(类似于事件) 自动更新 access_token
的方法,会在合适的时间点,触发信号,执行更新函数
信号机制由 blinker
库,blinker
是一个简洁的,为 Python 对象之间提供广播式的信号机制的库,必须先安装:
pip install blinker
就不展开 blinker
了,只要知道它是自动更新 access_token
需要依赖的库就行
from authlib.integrations.flask_client import token_update @token_update.connect_via(app) def on_token_update(sender, name, token, refresh_token=None, access_token=None): if refresh_token: item = OAuth2Token.find(name=name, refresh_token=refresh_token) elif access_token: item = OAuth2Token.find(name=name, access_token=access_token) else: return # 更新 access_token item.access_token = token[‘access_token‘] item.refresh_token = token.get(‘refresh_token‘) item.expires_at = token[‘expires_at‘] item.save()
flask_client
包中引入 token_update
类access_token
的回调函数 on_token_update
, 通过注解 token_update.connect_via
,注册成监听 access_token
更新事件的回调函数sender
是发出更新了 access_token
的实体,即认证服务器实例name
就是注册认证服务器的名称,即 oauth.register
的第一个参数token
为获得的新 access_token
对象refresh_token
和 access_token
之前通过认证时获得的,access_token
是旧的refresh_token
或 access_token
从查找之前的 token
记录,找到后,将新的 token
信息更新到记录中,并且保存。OAuth2Token
可以理解成库表对象,用来和库表交互,维护 token
对象启动 Flask 应用
python3 app.py
访问 http://localhost:5000
,如果一切正常,将看到页面上有个 login
连接,点击此连接,将跳转到认证页面,登录 Github(如果当前浏览器中没登录 Github 的话),将看到授权页面,类似于:
http://127.0.0.1:5000
也能访问,但是必须使用http://localhost:5000
来访问,即保持和注册时的首页 URL 一致
本节课程演示了 Flask 基于 Authlib 完成简单认证客户端的示例,是对前面 OAuth 理论的一次实践,主要需要了解客户端的结构和认证流程:
client_id
和 client_secret
access_token
的逻辑总体来说,认证客户端的实现不复杂,主要是概念比较绕,建议下载示例代码,实践一下,加深理解
关注公众号:python技术,回复"python"一起学习交流