Python request访问401错误与权限验证

最近,在使用Python requests接口访问开发的过程中,遇到401错误,跟踪原因是 Unauthorized ,这个错误通常意味着我在尝试访问某个资源时侯,没有提供正确的身份验证信息,或者你的身份验证信息已经过期。

在如此场景中,接口需要先进行登录操作以获取 AccessToken,然后使用这个 Token 来验证请求,同时,还可能需要签名等确保数据安全。如下图所示是我按此场景整理出来的访问处理过程程。

在这里插入图片描述

1. 带有身份验证的 Python 请求

Token是用于身份验证,通常通过 HTTP 请求头传递。在 requests 中,通常会直接处理 token的。

1.1. 发送登录请求以获取AccessToken

首先,你需要发送一个登录请求到服务器的登录端点,通常是一个POST请求,包含用户名和密码。服务器验证这些信息后,如果成功,会返回一个AccessToken。

python
import requests

# 登录URL
login_url = 'https://api.example.com/login'

# 登录数据,通常是用户名和密码
login_payload = {
    'username': 'your_username',
    'password': 'your_password'
}

# 发送登录请求
login_response= requests.post(login_url, json=login_payload)

# 检查请求是否成功
if response.status_code == 200:
    # 从响应中获取AccessToken
    access_token = login_response.json()['Data'].get('AccessToken')
    # 如果有RefreshToken,也一并保存
    refresh_token = login_response.json()['Data'].get('RefreshToken')

else:
    print('登录失败:', login_response.text)
    # 处理错误

1.2. 使用AccessToken发送请求

得到AccessToken,就可以在请求头中设置Authorization字段,并使用该Token来访问需要身份验证的资源。

# 资源URL
resource_url = 'https://api.example.com/protected_resource'

# 设置请求头,包含AccessToken
headers = {
    'Authorization': 'Bearer ' + access_token
}

# 发送请求
response = requests.get(resource_url, headers=headers)

# 检查请求是否成功
if response.status_code == 200:
    # 处理成功的响应
    print('请求成功:', response.json())
else:
    # 处理失败的响应,可能是Token过期或其他错误
    print('请求失败:', response.text)

1.3. Token刷新

如果AccessToken有有效期,并且快到期了,你需要使用RefreshToken来获取一个新的AccessToken。这个过程通常也是一个POST请求,发送到服务器的Token刷新端点。

# Token刷新URL
refresh_url = 'https://api.example.com/refresh_token'

# 设置请求头,包含RefreshToken
refresh_headers = {
    'Authorization': 'Bearer ' + refresh_token
}

# 发送Token刷新请求
refresh_response = requests.post(refresh_url, headers=refresh_headers)

# 检查请求是否成功
if refresh_response.status_code == 200:
    # 从响应中获取新的AccessToken
    new_access_token = refresh_response.json().get('access_token')
    # 更新Token
    access_token = new_access_token
else:
    print('Token刷新失败:', refresh_response.text)
    # 处理错误

2. 网络数据传输安全——对接口的数据进行MD5签名验证

我们在调用数据接口时,传输数据(或命令)做为一个文件,该文件使用MD5校验,那么在发送数据/文件的同时会再发一个存有校验码的文件,我们拿到该文件后做MD5运算,得到的计算结果与发送的校验码相比较,如果一致则认为发送的数据/文件没有出错,否则认为数据/文件出错需要重新发送。

要使用Python进行MD5加密,可以使用Python标准库中的hashlib模块。例如:

import hashlib
 
string = "Hello, World!"  # 要进行加密的字符串
 
hash_object = hashlib.md5(string.encode())  # 将字符串编码并进行 MD5 加密
hash_hex = hash_object.hexdigest()  # 获取加密后的十六进制字符串
 
print(hash_hex)  # 输出加密后的字符串

3. 实际应用案例

如上图所示,首先,使用登录接口API,获取Token;接着构造接口请求header,放入应用id、Token;再构造传输数据,并形成MD5验证密文;再把MD5验证密文做为签名放入header;最后,调用目标接口。实际应用案例如下(部分内容省略):

import requests, json
import datetime

def test():
      param = {
          "Id":"",
          "CreateTime":"2024-02-17 08:44:35",
          "AlarmValue":None,
          }  
      nowdate = datetime.datetime.now().strftime('%Y-%m-%d')      # 当前日期                   
      import uuid   

      # 登录
      login_headers = {'Content-Type':'application/json'}
      login_data = json.dumps(login_param)
      try:
          login_response = requests.post(cf.login_url, data=login_data, headers=login_headers, timeout=2)            
             
          # 检查登录是否成功
          if login_response.status_code == 200:
              print("登录成功")
              for vid in pveqid:
                  guid = str(uuid.uuid1())
                  dd = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                  # 提交数据
                  #headers = {'Content-Type':'application/json'}               
                  param['CreateTime'] = dd
                  param['AlarmValue'] = guid
                                    
                  data_json = json.dumps(param)
                  
                  sign = login_param['appId'] + dd + guid + str(data_json) + login_param['appSecret'] 
                  
                  import hashlib
                  hash_object = hashlib.md5(sign.encode())  # 将字符串编码并进行 MD5 加密
                  hash_hex = hash_object.hexdigest()  # 获取加密后的十六进制字符串
      
                  headers = {
                      'Authorization': 'Bearer ' + login_response.json()['Data']['AccessToken'],  
                      'Content-Type': 'application/json',
                      'appId': login_param['appId'],
                      'appSecret': login_param['appSecret'],
                      'time': dd,
                      'guid': guid,
                      'sign': hash_hex
                  }   
                               
                  try:
                      ret = requests.post(cf.alarmurl, data= data_json, headers=headers, timeout=2) # timeout超时2秒      
                      if  ret.status_code == 200:                
                          #ret_data = json.loads(ret.text)
                          ret_data = ret.json()                
                      else:
                          pass                   
                  except:   
                      pass         
          
          else:
              # 登录失败
              pass           
      except:   
          pass               

if __name__ == '__main__':
    test()

参考:

18.程序员. python使用MD5. CSDN博客. 2023.05