You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地Flask对接Clover API授权遇SSL/400错误求解决方案

本地Flask+Clover OAuth授权的HTTPS问题解决办法

问题背景

我正在搭建本地运行的基础库存管理应用,用localhost部署Flask,实现Clover API授权时遇到问题。生成自签名证书启用HTTPS后,仍出现400错误、请求版本错误,Chrome里报ssl_protocol_error。代码几乎是Clover官方示例,仅添加了证书和调试内容。

我的代码

import flask
import requests
import config
import os
from OpenSSL import SSL
ASSETS_DIR = os.path.dirname(os.path.abspath(__file__))

CLIENT_ID = config.CLIENT_ID
CLIENT_SECRET = config.CLIENT_SECRET
ENV = "https://sandbox.dev.clover.com"

if not CLIENT_ID or not CLIENT_SECRET:
    raise ValueError("Set your CLIENT_ID and CLIENT_SECRET in config.py.")

app = flask.Flask(__name__)

context = SSL.Context(SSL.SSLv23_METHOD)
context.use_privatekey_file('crt/key.pem')
context.use_certificate_file('crt/certificate.pem')

app.config['APPLICATION_ROOT'] = '/'

app.config['PREFERRED_URL_SCHEME'] = 'https'


@app.route("/", methods=["GET"])
def landing_page():
    """Depending on whether `code` parameter is present, redirects to
    oauth_callback or to Clover merchant login."""

    # A request from an authorized merchant includes a code in its query string.
    code = flask.request.args.get("code")

    # If the request doesn't include a code, redirect the merchant to Clover's
    # authorize endpoint.
    if not code:
        return flask.redirect("%s/oauth/authorize?client_id=%s" % (ENV, CLIENT_ID))

    # If the request does include a code, redirect to this app's oauth_callback
    # in order to request an access_token.
    else:
        return flask.redirect("/oauth_callback?code=%s" % code)


@app.route("/oauth_callback", methods=["GET"])
def oauth_callback():
    """Uses `code` with CLIENT_ID and CLIENT_SECRET to request access_token."""

    code = flask.request.args.get("code")

    # The merchant shouldn't reach this endpoint without a code, but just in case:
    if not code:
        return flask.redirect("/")

    # Use the code with your app ID and app secret to request an access_token.
    request = "%s/oauth/token?client_id=%s&client_secret=%s&code=%s" % (ENV, CLIENT_ID, CLIENT_SECRET, code)

    try:
        response = requests.get(request)
        response.raise_for_status()
        access_token = response.json().get("access_token")
        print("Access token: ", access_token)
        
        if access_token:
            return "Access token: " + access_token
        else:
            return "Could not retrieve access_token."
    except requests.RequestException as e:
        print("Request failed:", e)
    except Exception as e:
        print(e)


################################################################################

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000, debug=True, ssl_context=context)

错误日志

127.0.0.1 - - [12/Feb/2024 19:09:57] code 400, message Bad request version ('**\x13\x01\x13\x02\x13\x03À+À/À,À0̨̩À\x13À\x14\x00\x9c\x00\x9d\x00/\x005\x01\x00\x01\x9f\x1a\x1a\x00\x00\x00')
127.0.0.1 - - [12/Feb/2024 19:09:57] "\x16\x03\x01\x02\x0c\x01\x00\x02\x08\x03\x03­9Kmñx\x00=;G¢Ë¬\x95\x9c>)\x91ZSqîÝ%µÈ\x86OÞ\x1f>× \x96Büo\x08H4¡6ÆÎÈ´ö¡fÐÔ\x8552È\x00uÚ$ߪàss·\x00 **\x13\x01\x13\x02\x13\x03À+À/À,À0̨̩À\x13À\x14\x00\x9c\x00\x9d\x00/\x005\x01\x00\x01\x9f\x1a\x1a\x00\x00\x00" 400 - 

解决办法

1. 简化SSL上下文配置

Flask内置支持直接传入证书文件路径,无需手动构建OpenSSL Context,这能避免协议版本不兼容问题:

# 删除原有的context创建代码
# context = SSL.Context(SSL.SSLv23_METHOD)
# context.use_privatekey_file('crt/key.pem')
# context.use_certificate_file('crt/certificate.pem')

# 修改启动代码,直接传入证书元组
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000, debug=True, ssl_context=('crt/certificate.pem', 'crt/key.pem'))

2. 重新生成合规的自签名证书

用OpenSSL生成符合现代TLS标准的证书,确保Common Name设置为localhost:

openssl req -x509 -newkey rsa:4096 -nodes -out crt/certificate.pem -keyout crt/key.pem -days 365

3. 核对Clover回调地址

在Clover开发者后台,将应用的OAuth回调地址设置为https://localhost:5000/oauth_callback,确保与代码中的路由完全匹配。

4. 本地开发的简便替代方案

用ngrok转发本地HTTP服务到HTTPS,绕开本地证书配置:

  1. 启动Flask的HTTP服务(移除ssl_context参数):
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000, debug=True)
  1. 运行ngrok转发端口:
ngrok http 5000
  1. 将Clover后台的回调地址替换为ngrok提供的HTTPS地址(例如https://xxxx-xx-xx-xx-xx.ngrok.io/oauth_callback)。

5. 指定兼容的SSL协议版本

如果坚持手动配置SSL Context,指定使用TLS 1.2或更高版本:

from OpenSSL import SSL
context = SSL.Context(SSL.TLSv1_2_METHOD)  # 使用现代TLS协议
context.use_privatekey_file('crt/key.pem')
context.use_certificate_file('crt/certificate.pem')

内容的提问来源于stack exchange,提问作者jon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 02:32:02