Mrli
别装作很努力,
因为结局不会陪你演戏。
Contacts:
QQ博客园

Oauth2原理、使用

2019/09/15 flask 后端 Web
Word count: 1,334 | Reading time: 5min

Oauth2原理、使用

原理

快递员–>门禁–>小区–>我家 <=====> 第三方应用 --> 微信墙 —>账号–>个人数据

简单说,OAuth 就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。

OAuth 的核心就是向第三方应用颁发令牌

令牌特点:

(1)令牌是短期的,到期会自动失效,用户自己无法修改。密码一般长期有效,用户不修改,就不会发生变化。

(2)令牌可以被数据所有者撤销,会立即失效。以上例而言,屋主可以随时取消快递员的令牌。密码一般不允许被他人撤销。

(3)令牌有权限范围(scope),比如只能进小区的二号门。对于网络服务来说,只读令牌就比读写令牌更安全。密码一般是完整权限。

OAuth是什么?

引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者。…资源所有者同意以后,资源服务器可以向客户端颁发令牌。客户端通过令牌,去请求数据。

四种获得令牌的流程:

  • 授权码(authorization-code)

    • 1.发送请求A->B

      • 1
        2
        3
        4
        5
        https://b.com/oauth/authorize?
        response_type=code&
        client_id=CLIENT_ID&
        redirect_uri=CALLBACK_URL&
        scope=read
      • A(客户端)->B()response_type参数表示要求返回授权码(code),client_id参数让 B 知道是谁在请求,redirect_uri参数是 B 接受或拒绝请求后的跳转网址,scope参数表示要求的授权范围(这里是只读)。

    • 第二步,用户跳转后,B 网站会要求用户登录,然后询问是否同意给予 A 网站授权。用户表示同意,这时 B 网站就会跳回redirect_uri参数指定的网址。跳转时,会传回一个授权码,就像https://a.com/callback?code=AUTHORIZATION_CODE

    • 第三步,A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。

      • 1
        2
        3
        4
        5
        6
        https://b.com/oauth/token?
        client_id=CLIENT_ID&
        client_secret=CLIENT_SECRET&
        grant_type=authorization_code&
        code=AUTHORIZATION_CODE&
        redirect_uri=CALLBACK_URL

        上面 URL 中,client_id参数和client_secret参数用来让 B 确认 A 的身份(client_secret参数是保密的,因此只能在后端发请求),grant_type参数的值是AUTHORIZATION_CODE,表示采用的授权方式是授权码,code参数是上一步拿到的授权码,redirect_uri参数是令牌颁发后的回调网址。

    • 第四步,B 网站收到请求以后,就会颁发令牌。具体做法是向redirect_uri指定的网址,发送一段 JSON 数据。

      • 1
        2
        3
        4
        5
        6
        7
        8
        9
        {    
        "access_token":"ACCESS_TOKEN",
        "token_type":"bearer",
        "expires_in":2592000,
        "refresh_token":"REFRESH_TOKEN",
        "scope":"read",
        "uid":100101,
        "info":{...}
        }

        上面 JSON 数据中,access_token字段就是令牌,A 网站在后端拿到了。

  • 隐藏式(implicit)

    • 有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。

    • 1
      2
      3
      4
      5
      https://b.com/oauth/authorize?
      response_type=token&
      client_id=CLIENT_ID&
      redirect_uri=CALLBACK_URL&
      scope=read

      response_type参数为token,表示要求直接返回令牌。

    • https://a.com/callback#token=ACCESS_TOKEN``token参数就是令牌,A 网站因此直接在前端拿到令牌。

    • ▲注意,令牌的位置是 URL 锚点(fragment),而不是查询字符串(querystring),这是因为 OAuth 2.0 允许跳转网址是 HTTP 协议,因此存在"中间人攻击"的风险,而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险。

  • 密码式(password):

    • 如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。

  • 客户端凭证(client credentials)

    • 适用于没有前端的命令行应用,即在命令行下请求令牌。

clientID和ClientSecret均是App需要申请的API密钥

Oauth_ClientID

使用

Github Oauth

QQ Oauth

本地测试QQ的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 方法一:在hosts中将nymrli.top修改到127.0.0.1
@app.route('/login')
def login():
params = {
'response_type' : 'code',
'client_id' : '101568872',
'redirect_uri' : 'http://beta.nymrli.top/oauth/qq',
'state' : '1',
}
url = 'https://graph.qq.com/oauth2.0/authorize?'
urlParams = urlencode(params)
# ▲需要url编码
comleteUrl = url + urlParams
# return url_for( )
'''
▲应该用redirect,而不是requests.get的text内容或者是url_for
'''
return redirect( comleteUrl)

@app.route('/oauth/qq')
def getCode():
return request.args.get('code')

# 方法二:随便申请一个应用
@app.route('/login')
def login():
params = {
'response_type' : 'code',
'client_id' : '101584056',
# 'redirect_uri' : 'http://beta.nymrli.top/oauth/qq',
'redirect_uri' : 'http://127.0.0.1:8000/oauth/redirect',
'state' : 'test'
}
url = 'https://graph.qq.com/oauth2.0/authorize?'
urlParams = urlencode(params)
comleteUrl = url + urlParams
return redirect( comleteUrl)


@app.route('/oauth/redirect')
def getCode():
print(request.args)
return 'hello'

QQoauth_test

坑点记录:部署

经过调试发现部署上去后,在http://beta.nymrli.top/info页面下获得不到 access_token = session.get('access_token')于是猜想session设置有问题。果然linux下os.urandom(24)有问题, 结果是无法获得到信息。经修改后能正常获得结果

1
SECRET_KEY= os.urandom(24)  # 设置为24位的字符,每次运行服务器都是不同的,所以服务器启动一次上次的session就清除。

no

改成随便的SECRET_KEY的就行了,比如SECRET_KEY='asdzxcqwe'

Author: Mrli

Link: https://nymrli.top/2019/06/03/Oauth2原理、使用/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
Python的构建工具setup.py
NextPost >
lua学习
CATALOG
  1. 1. Oauth2原理、使用
  2. 2. 原理
    1. 2.1. OAuth 的核心就是向第三方应用颁发令牌
      1. 2.1.1. 令牌特点:
    2. 2.2. OAuth是什么?
    3. 2.3. 四种获得令牌的流程:
  3. 3. 使用
    1. 3.1. Github Oauth
    2. 3.2. QQ Oauth
      1. 3.2.1. 坑点记录:部署