Django OAuth Toolkit
使用说明
B依托Django OAuth Toolkit, 具备作为OAuth2.0服务器能力, 第三方网站/系统/服务/APP, 可以利用该能力, 获取用户登录信息, 各类资源.
假设你拥有一个系统A, 希望在系统A的导航条中增加一个按钮, “使用B登录”, 点击后, 用户可以利用B帐号登录系统A, 并获取用户信息和B可向系统A暴露的其他信息.
具体来说, 用户会访问系统A(a), 点击”使用B登录”, 并被跳转到B登录页(b), 如果用户没有登录B, 需要输入用户名密码, 否则用户被询问是否允许使用B帐号登录系统A(c), 用户点击允许, 并跳转回系统A(d), 系统A获得Token, 可以访问用户信息等B接口(e).
了解一些背景知识
OAuth2.0是一种非常通用的工业级授权方式(OAuth 2.0 is the industry-standard protocol for authorization.) 如果你从未听过, 可以参考下列资料做一个粗略了解:
在B注册系统A
注册并登录B.
打开OAuth应用注册页面 你的服务地址/oauth2/applications/
, 点New Application
其中Name填自己的应用名称, Client id和Client secret可以用自动生成的.
-
name:应用名称
-
Client id、Client secret自动生成
-
Client type :公开还是机密
-
Authorization grant type 一共有四种
-
授权码(authorization-code):指的是第三方应用先申请一个授权码,然后再用该码获取令牌,这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。一般针对于用户。此种方式见后面详细介绍。
-
隐藏式(implicit):有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端
-
密码式(password):如果你高度信任某个应用,也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌
-
客户端凭证(client credentials):最后一种方式是凭证式(client credentials),适用于没有前端的命令行应用,即在命令行下请求令牌。这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。
可直接通过client_id和secret直接获取token
# body { "client_id": "xxx", "client_secret": "xxx", "redirect_uri": "http://django-oauth-toolkit.herokuapp.com/consumer/exchange/", "grant_type": "client_credentials" }
-
-
Redirect uris:访问以后跳转的地址。
授权码(authorization-code)方式
授权码方式使用
所谓落地页, 就是访问授权后用户回到的页面.
如果你还没开始开发, 可以先用这个网站试一试, 本页面会生成一个链接,点击后会跳转到授权页面。
在例子中, 落地页应该填: http://django-oauth-toolkit.herokuapp.com/consumer/exchange/
最后点保存, 就完成了B侧的应用注册.
显然, 你需要记下来自己的Client id和Client secret.
用户将看到一个这样的页面(可以通过django国际化进行汉化):
用户点击授权之后, 将会被重定向到你的落地页, 并在url中携带code
在例子中, 应该在该页面, 输入你的Client id和授权url:
你的域名/oauth2/authorize
, 然后获得重定向地址, 并跳转到如下页面
你的落地页后端拿到code之后, 需要请求token, 也就是你的落地页后端需要发一个POST请求:
fetch(new Request('你的域名/oauth2/token/',{
method:'POST',
headers: {'Cache-Control': 'no-cache',
'Content-Type':'application/x-www-form-urlencoded'},
body:{
'client_id':'3RGYcLX5nj9vMT0UbjxjXmYikNrOwEEH2uofF6gq',
'client_secret':'Wu0tcWSpPk3AqUVw1FFS7zWuibEOxELlCp8AtQDPfq2qo991eH8oIGluFSDStEO80ndzWV32e5szIpyNWM5auj8HFTFrzqqnmYo5pYzuI6fFcKdfj90blHgMYivAgWLp',
'code':'yiKoD7Ms1EvE2dgj5dP51MepkJPFty',
'redirect_uri':'http://django-oauth-toolkit.herokuapp.com/consumer/exchange/',
'grant_type':'authorization_code'
}
})).then((resp)=>{console.log(resp)})
这一步的目的是将明文传输的CODE换成服务器之间传递的TOKEN, 你可以开发另一个落地页2, 或者通过参数复用同一个落地页, 为防混乱, 在本文档中, 我们使用落地页2描述上述POST请求中的${YOUR_CALLBACK_PAGE}
在例子中, 你需要60秒内手动发送上述POST请求, 但是在正式集成中, 应该由落地页的后端自动发送, 按F12打开浏览器调试工具, 填上一个图片中右边的表单, token url是
你的域名/oauth2/token/
点Submit, 就能看到你发出了上述POST请求.
上述POST将给你如下返回值:
{
"access_token": "aVvBRVFMWPYhZPczNlaWdPTyT5g8Fk",
"expires_in": 36000,
"token_type": "Bearer",
"scope": "read write"
}
凭上述access_token, 用户可以访问B中该用户全部授权资源, 例如, 落地页2应该访问下面API, 获取并展示用户信息, 完成系统A的登录:
跳过授权码
该方式需要你完全信任对方,可避免弹窗出现。在Applications的model中将skip_authorization = True,可在admin的后台操作。
获取用户信息接口
url: /api/v2/user/
method: GET
header:
{"Authorization": "Bearer QUgU1t5MvaRuuMtaGy8gTCm3dtdGGL"}
Response
{
"email": "dfsdfzza@phytium.com.cn",
"password": "123",
"last_login": null,
"username": "fgfdsaasd",
"last_name": "发给对方",
"date_joined": "2020-07-23T02:12:34.588741"
}
后端代码
这样就能返回用户自己的信息了。
class UsersSerializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = '__all__'
depth = 1
class UserDetail(generics.GenericAPIView):
authentication_classes = [OAuth2Authentication]
def get(self, req, *args, **kwargs):
user = req.user.users
serializer = UsersSerializer(instance=user)
data = serializer.data
data['user'].pop('password')
return Response(serializer.data)