Flutter中如何实现给定cURL请求并正确配置consumer密钥
Flutter 对接钱包 OAuth2 接口实现方案
核心配置说明
consumer key、consumer secret仅在第一步调用token接口获取access_token时使用:将两个值用英文冒号拼接为consumer-key:consumer-secret格式,做Base64编码后放在该接口的Authorization: Basic <编码后字符串>请求头中- 后续所有业务接口(包含钱包开户接口)不需要传递consumer key/secret,仅需将第一步获取到的有效access_token放在
Authorization: Bearer <access_token>请求头中即可 - 你拿到的开户示例cURL中写死的
c9b84e30-e59a-3789-b6d1-3595552dfb23为演示用token,实际调用必须替换为动态获取的有效token
前置依赖
在pubspec.yaml中添加网络请求相关依赖:
dependencies: flutter: sdk: flutter http: ^1.2.0 # 可替换为最新稳定版本
第一步:实现access_token获取逻辑
对应官方提供的Password Grant类型cURL示例,注意该接口请求体为表单格式,不是JSON格式:
import 'dart:convert'; import 'package:http/http.dart' as http; /// 调用token接口获取访问令牌 /// [consumerKey] 平台分配的consumer key /// [consumerSecret] 平台分配的consumer secret /// [username] 你的平台登录账号 /// [password] 你的平台登录密码 Future<String> getAccessToken({ required String consumerKey, required String consumerSecret, required String username, required String password, }) async { // 处理Basic认证头 final basicAuthBytes = utf8.encode('$consumerKey:$consumerSecret'); final basicAuthStr = base64Encode(basicAuthBytes); final response = await http.post( Uri.parse('https://devesb.elicia.systems:8263/token'), headers: { 'Authorization': 'Basic $basicAuthStr', 'Content-Type': 'application/x-www-form-urlencoded', }, body: { 'grant_type': 'password', 'username': username, 'password': password, }, ); if (response.statusCode != 200) { throw Exception('获取access_token失败,状态码:${response.statusCode},返回:${response.body}'); } final respData = jsonDecode(response.body); return respData['access_token']; }
注意:官方cURL中携带
-k参数代表忽略SSL证书校验,如果测试环境使用自签证书,会触发CERTIFICATE_VERIFY_FAILED错误,可在测试阶段全局配置跳过证书校验,生产环境必须移除该配置。跳过校验的实现代码见文末踩坑点。
第二步:实现钱包开户接口调用
对应你拿到的开户cURL,该接口请求体为JSON格式,不需要传递consumer key/secret:
/// 调用钱包开户接口 /// [accessToken] 第一步获取的有效访问令牌 Future<Map<String, dynamic>> createWallet({ required String accessToken, required String signupUsername, required String walletName, required String webhookUrl, required String shortName, // 固定4位字符长度 required String implementation, // 仅支持传'POOL'或'1-1' }) async { final response = await http.post( Uri.parse('https://devesb.vfdbank.systems:8263/vfd-wallet/1.1/wallet2/onboarding?wallet-credentials=wallet-credentials'), headers: { 'accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': 'Bearer $accessToken', }, body: jsonEncode({ 'username': signupUsername, 'walletName': walletName, 'webhookUrl': webhookUrl, 'shortName': shortName, 'implementation': implementation, }), ); if (response.statusCode < 200 || response.statusCode >= 300) { throw Exception('开户接口调用失败,状态码:${response.statusCode},返回:${response.body}'); } return jsonDecode(response.body); }
调用示例
void main() async { // 测试环境自签证书处理,生产环境删除 // HttpOverrides.global = _IgnoreCertOverride(); try { final token = await getAccessToken( consumerKey: '你的consumerKey', consumerSecret: '你的consumerSecret', username: '你的平台账号', password: '你的平台密码', ); final walletInfo = await createWallet( accessToken: token, signupUsername: '开户用用户名', walletName: '企业/钱包名称', webhookUrl: '通知回调地址', shortName: 'WLT1', // 4位字符 implementation: 'POOL', ); print('开户成功:$walletInfo'); } catch (e) { print('调用出错:$e'); } }
常见踩坑点
- 不要将consumer key/secret放在开户接口的请求头、请求参数或请求体中,这两个值仅用于换token的接口
- 获取token的接口必须用
application/x-www-form-urlencoded格式传参,传JSON会报grant_type无效错误 - 开户接口必须用
application/json格式传参,不要传表单格式 - shortName字段必须严格传4位字符,implementation字段只能传接口约定的两个枚举值,否则会报参数错误
- 测试环境自签证书跳过校验实现:
import 'dart:io'; class _IgnoreCertOverride extends HttpOverrides { @override HttpClient createHttpClient(SecurityContext? context) { return super.createHttpClient(context) ..badCertificateCallback = (cert, host, port) => true; } }
内容的提问来源于stack exchange,提问作者My snow
相关产品推荐
相关产品推荐

