Skip to content
Go back

使用 Python3 实践 Dropbox 生成刷新令牌 (Refresh Token) 以实现长久访问

| 0 Views Edit page

前言

Easycrawl 的预览和下载功能将基于 Dropbox 实现,免人工维护、可以长久使用的 Token 是绝对必要的。
但是由于自 Dropbox 使用 OAuth 2.0 进行授权后就停止生成长寿命的 access_tokenMigrating App Permissions and Access Tokens,因此只能使用过期前刷新令牌的方式来实现永久访问了。


方案概述

  1. OAuth 2.0 授权模式下的基础概念
  2. 新建 Dropbox App 并获取各值
  3. 刷新令牌实现流程的可视化
  4. 使用 Python3 实现令牌的自动刷新

详细内容

一、OAuth 2.0 授权模式下的基础概念

1、(short-lived) access token

短期访问令牌,所有的 Dropbox API 请求都需要携带 access_token 作为身份验证。
默认生成的 access_token 有效期为 4 小时,过期后需要重新获取。

2、refresh token

刷新令牌,可以用来获取新的 access_token
refresh_token 永不过期,可以一直使用,除非用户撤销应用的访问权限。
refresh_token 只能通过 OAuth 2.0 授权流程获取一次,之后需要妥善保存。

3、app key 和 app secret

app_keyapp_secret 是应用的唯一标识和密钥,用于身份验证。
app_key 是公开的,可以在客户端代码中使用。
app_secret 是私密的,必须保存在服务器端,不能暴露给客户端。

4、OAuth 2.0 授权流程

  1. 用户访问应用,应用引导用户到 Dropbox 的授权页面,用户登录并授权应用访问其 Dropbox 账户。授权成功后,Dropbox 重定向用户回应用,并附带一个授权码(后续代码中标识为 access_code)。
  2. 应用使用授权码向 Dropbox 请求 access_tokenrefresh_token
  3. 应用使用 access_token 访问 Dropbox API。
  4. access_token 过期后,应用使用 refresh_token 请求新的 access_token

二、新建 Dropbox App 并获取各值

前往 App 控制台:App Console - Dropbox ceshiku_01.png
ceshiku_02.png

之后就获取到了值

  • app_key: 1jhdvh6zytcXXXX
  • app_secret: g7nox5hlfb6XXXX

OAuth 2 认证后的重定向链接不用管,不是必要的。

三、刷新令牌实现流程的可视化

Excalidraw 可视化

四、使用 Python3 实现令牌的自动刷新

import requests


APP_KEY = "1jhdvh6zytcxxxx"
APP_SECRET = "g7nox5hlfb6xxxx"


def _first_get_access_code():
    url = "https://www.dropbox.com/oauth2/authorize" \
        + "?client_id={}".format(APP_KEY) \
        + "&token_access_type=offline" \
        + "&response_type=code"
    access_code = input("Go to the following URL and authorize the app:\n{}\nThen enter the code here: ".format(url))
    return access_code

def _second_get_refresh_token(access_code):
    url = "https://api.dropboxapi.com/oauth2/token"
    data = {
        "code": access_code,
        "grant_type": "authorization_code",
        "client_id": APP_KEY,
        "client_secret": APP_SECRET,
    }
    response = requests.post(url, data=data)
    print("> Response Status Code:", response.status_code)
    print("> Response Text:", response.text)  # > Response Text: {"access_token": "sl.xxx", "refresh_token": "xxxx"...
    refresh_token = response.json().get("refresh_token")
    return refresh_token
    
def _third_refresh_access_token(refresh_token):
    url = "https://api.dropboxapi.com/oauth2/token"
    data = {
        "refresh_token": refresh_token,
        "grant_type": "refresh_token",
        "client_id": APP_KEY,
        "client_secret": APP_SECRET,
    }
    response = requests.post(url, data=data)
    print("> Response Status Code:", response.status_code)
    print("> Response Text:", response.text)  # > Response Text: {"access_token": "sl.xxx", "token_type": "bearer"...
    access_token = response.json().get("access_token")
    return access_token

def _fourth_use_access_token(access_token):
    url = "https://api.dropboxapi.com/2/users/get_current_account"
    headers = {
        "Authorization": "Bearer {}".format(access_token)
    }
    response = requests.post(url, headers=headers)
    print("> Response Status Code:", response.status_code)
    print("> Response Text:", response.text)  # > Response Text: {"account_id": "dbid:xxxx", "name": {"given_name": "xxx"...


def main():
    """
    主方法
    """
    # 1. 获取 access code
    access_code = _first_get_access_code()
    print("Access Code:", access_code)  # Access Code: gUeuzCLrRU0AAAAAAAAAGr8nqqMK3qcwhu4ZbaEXXXX
    # 注意 access_code 只能使用一次
    # 因此每次获取之后的 refresh_token 都需要重新获取 access_code

    # 2. 用 access code 换取 refresh token
    refresh_token = _second_get_refresh_token(access_code)
    print("Refresh Token:", refresh_token)  # Refresh Token: P7vSxBhf2FEAAAAAAAAAAQ_vXY2SQecMN_sCvhZuDea2N-1VofCZzSVgSSPwXXXX

    # 3. 保存 refresh token 到安全的地方,后续可以用它来获取新的 access token
    with open("dropbox_refresh_token.txt", "w") as f:
        f.write(refresh_token)
    access_token = _third_refresh_access_token(refresh_token)
    print("Access Token:", access_token)  # Access Token: sl.AF_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    # 4. 使用 access token 访问 Dropbox API
    _fourth_use_access_token(access_token)

    # 之后超过 4 小时后,再次实行第二部的刷新令牌


if __name__ == "__main__":
    main()

Edit page