Authlib强大OAuth框架入门

基于Python的Authlib是集所有主流WebAPI权限认证协议的客户端、服务端、底层实现、高层架构于一身的强大工具库。

参考官方:Authlib: Python Authentication

Authlib几乎是能将RFC所有相关的API认证协议都包括进来了,甚至从协议的底层实现、高层架构,从客户端到服务端都能实现的,当之无愧称为Monolithic project 的一个项目。

目前Authlib支持的Authentication协议有:

  • OAuth 1.0
  • OAuth 2.0
  • JWT
  • many more...

安装:

$ pip install Authlib

Oauth2.0客户端验证

参考官方:Authlib - Client Guide - OAuth 2 Session

Authlib中用来登录验证OAuth2.0的对象叫Session,其中包括了所有相关的验证所需方法函数。

from authlib.client import OAuth2Session

# 生成session,用来之后的创建URL、获取token、刷新token等所有动作
session = OAuth2Session(
    client_id='Your Client ID', client_secret='Your Client Secret',
    scope='user:email',  # 这个授权范围根据每个API有所不同
    redirect_uri='https://MyWebsite.com/callback'
)


# 生成URL
uri, state = session.create_authorization_url(
    'https://目标网址的授权入口/authorize'
)
print(uri)

# 「手动」打开浏览器访问URI,登录API帐户,点击授权,然后获取最终的URL
# 或者自己有服务器的话,可以自己接收
#。。。
# 将callback返回的URL复制下来,因为其中包含授权code
authorization_response = 'https://MyWebsite.com/callback?code=42..e9&state=d..t'

# 用获得的Code去访问access_token入口
tokens = session.fetch_access_token(
    access_token_url='https://目标网址的授权入口/api/access_token',
    authorization_response=authorization_response
)
print(tokens)  #返回字典格式: {'access_token': 'e..ad', 'token_type': 'bearer', 'scope': 'user:email'}


# 过期后,刷新token。需重建session对象:
session = OAuth2Session(
    client_id='Your Client ID', client_secret='Your Client Secret',
    scope='user:email', state=state, redirect_uri='https://MyWebsite.com/callback'
)
new_tokens = session.refresh_token(
    access_token_url, refresh_token=tokens['refresh_token']
)
print('[Refreshed tokens]:', new_tokens)

设置的callback或redirect_url不存在怎么获取Code?

在调试过程中,如果我们向上面一样手动去打开浏览器复制URL,再复制回应过来的URL是很麻烦的。

Oauth2的逻辑就是:要求各种客户自己在自己的浏览器里登录帐户,然后给你的App授权。所以这一步redirect_url是躲不过的。但是我们测试过程中,还没来得及专门建一个服务器或网页来接收这个callback回调怎么办呢?
有办法!

方法一:直接截取

我们可以在第一次登录并授权后,复制cookies,然后在测试中直接使用requests带着cookies登录信息去访问,就不再需要手动打开浏览器了:

raw_cookies = """ 这里是你复制过来的cookies """
cookies = dict([line.split("=", 1) for line in raw_cookies.strip().split("; ")])

try:
    r = requests.get(uri, cookies=cookies, allow_redirects=True)
except requests.exceptions.ConnectionError as e:
    print( '[Final URL]: ', e.request.url )
    authorization_response = e.request.url

由于你最开始设置的callback是公网上的某个网址,应该是不存在的(只要你没有设置的话)。
所以,这里去request的时候,肯定会报错,且是ConnectionError。所以我们可以将最终报错的URL获取到,这个里面就包含了我们想要的Code码。

方法二:更改本地hosts

如果本地已经搭建了测试服务器,比如Nginx或Flask,这种方法更简单。

比如在供应商中设定的redirect_url为http://example.com/callback,那么只需简单编辑hosts:

# /etc/hosts

127.0.0.1   example.com

那么,只要本机设置了Nginx或Flask等服务器,只需要获取127.0.0.1/callback即可得到需要的内容。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了搭建OAuth2服务器,您可以使用现有的OAuth2服务器实现,例如AuthlibOAuthlib。以下是使用Authlib搭建OAuth2服务器的步骤: 1.安装Authlib ```shell pip install authlib ``` 2.创建一个Flask应用程序 ```python from flask import Flask app = Flask(__name__) ``` 3.配置应用程序 ```python from authlib.integrations.flask_oauth2 import AuthorizationServer from authlib.integrations.sqla_oauth2 import create_query_client_func from flask_sqlalchemy import SQLAlchemy app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///oauth2.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SECRET_KEY'] = 'secret-key' app.config['OAUTH2_REFRESH_TOKEN_GENERATOR'] = True db = SQLAlchemy(app) class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(40), unique=True) password = db.Column(db.String(100)) class Client(db.Model): id = db.Column(db.Integer, primary_key=True) client_id = db.Column(db.String(40), unique=True) client_secret = db.Column(db.String(55), nullable=False) client_name = db.Column(db.String(100), nullable=False) is_confidential = db.Column(db.Boolean) def get_client_id(self): return self.client_id def get_client_secret(self): return self.client_secret def check_redirect_uri(self, redirect_uri): return True def has_user_consent(self, user, scope): return True def get_default_redirect_uri(self): return 'http://localhost:5000/authorized' class OAuth2Client(db.Model): id = db.Column(db.Integer, primary_key=True) client_id = db.Column(db.String(40), db.ForeignKey('client.client_id')) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) user = db.relationship(User) client = db.relationship(Client) token_type = db.Column(db.String(40)) access_token = db.Column(db.String(255)) refresh_token = db.Column(db.String(255)) expires_at = db.Column(db.DateTime) query_client = create_query_client_func(db.session, Client) authorization = AuthorizationServer(app, query_client=query_client) ``` 4.实现授权和令牌端点 ```python from flask import jsonify, request from authlib.oauth2 import OAuth2Error from authlib.oauth2.rfc6749 import grants @app.route('/oauth/token', methods=['POST']) def issue_token(): grant_type = request.form.get('grant_type') if grant_type == 'password': return grants.ResourceOwnerPasswordCredentialsGrant().create_token_response() elif grant_type == 'client_credentials': return grants.ClientCredentialsGrant().create_token_response() elif grant_type == 'refresh_token': return grants.RefreshTokenGrant().create_token_response() raise OAuth2Error('unsupported_grant_type') @app.route('/oauth/authorize', methods=['GET', 'POST']) def authorize(): if request.method == 'GET': try: grant = authorization.validate_consent_request(end_user=User.query.get(1)) return grant.prompt except OAuth2Error as error: return jsonify(dict(error.get_body())) if request.method == 'POST': if request.form['confirm']: grant_user = User.query.get(1) return authorization.create_authorization_response(grant_user=grant_user) return jsonify({'error': 'User denied authorization'}) ``` 5.运行应用程序 ```shell export FLASK_APP=app.py flask run ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值