Dart OAuth 1.0 - 无效签名 - 提供的签名不匹配
Posted
技术标签:
【中文标题】Dart OAuth 1.0 - 无效签名 - 提供的签名不匹配【英文标题】:Dart OAuth 1.0 - Invalid signature - provided signature does not match 【发布时间】:2020-10-23 19:43:00 【问题描述】:我正在使用 OAuth 1.0 调用 api,并且我正在使用以下包进行 api 调用。但我收到以下错误。请任何人指导我修复此错误。
api调用库:
https://github.com/nbspou/dart-oauth1
我的代码:
const String apiKey = 'ck_789b63aee985c4569bfa5ae4724861ae5c74c337';
const String apiSecret = 'cs_0f0addbc9c16042d5689a4cfe6fbfd209b00d55b';
var clientCredentials = new oauth1.ClientCredentials(Uri.encodeComponent(apiKey), Uri.encodeComponent(apiSecret));
// create Authorization object with client credentials and platform definition
//var auth = new oauth1.Authorization(clientCredentials, platform);
var auth = new oauth1.Credentials(apiKey, apiSecret);
// yeah, you got token credentials
// create Client object
var client = new oauth1.Client(platform.signatureMethod, clientCredentials, auth);
// now you can access to protected resources via client
client.get('http://demo2.signitydemo.in/foodemporium/wp-json/wc/v3/products/categories').then((res)
print("res.body===$res.body");
print("statusCode===$res.statusCode");
print("headers===$res.headers");
);
"code":"woocommerce_rest_authentication_error","message":"Invalid signature - provided signature does not match.","data":"status":401
标题:
link: <http://demo2.signitydemo.in/foodemporium/wp-json/>; rel="https://api.w.org/", access-control-allow-headers: Authorization, Content-Type, connection: keep-alive, date: Fri, 03 Jul 2020 05:32:04 GMT, transfer-encoding: chunked, vary: Origin, access-control-expose-headers: X-WP-Total, X-WP-TotalPages, x-robots-tag: noindex, content-type: application/json; charset=UTF-8, x-content-type-options: nosniff, server: nginx
我已经在 Postman 中测试过 API。它工作正常,我得到了回应。请参阅下面的邮递员 API 请求。
【问题讨论】:
【参考方案1】:所以我放弃了 Woocommerce 包来创建一个函数,该函数使用 oauth 1.0 身份验证的新参数解析 url
import 'dart:collection';
import 'dart:math';
import 'package:crypto/crypto.dart' as crypto;
import 'package:http/http.dart' as http;
import 'dart:convert';
/// This Generates a valid OAuth 1.0 URL
///
/// if [isHttps] is true we just return the URL with
/// [consumerKey] and [consumerSecret] as query parameters
String _getOAuthURL(String requestMethod, String queryUrl)
String consumerKey = cKey;
String consumerSecret = cSecret;
String token = "";
String url = queryUrl;
bool containsQueryParams = url.contains("?");
Random rand = Random();
List<int> codeUnits = List.generate(10, (index)
return rand.nextInt(26) + 97;
);
/// Random string uniquely generated to identify each signed request
String nonce = String.fromCharCodes(codeUnits);
/// The timestamp allows the Service Provider to only keep nonce values for a limited time
int timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
String parameters = "oauth_consumer_key=" +
consumerKey +
"&oauth_nonce=" +
nonce +
"&oauth_signature_method=HMAC-SHA1&oauth_timestamp=" +
timestamp.toString() +
"&oauth_token=" +
token +
"&oauth_version=1.0&";
if (containsQueryParams == true)
parameters = parameters + url.split("?")[1];
else
parameters = parameters.substring(0, parameters.length - 1);
Map<dynamic, dynamic> params = QueryString.parse(parameters);
Map<dynamic, dynamic> treeMap = new SplayTreeMap<dynamic, dynamic>();
treeMap.addAll(params);
String parameterString = "";
for (var key in treeMap.keys)
parameterString = parameterString +
Uri.encodeQueryComponent(key) +
"=" +
treeMap[key] +
"&";
parameterString = parameterString.substring(0, parameterString.length - 1);
String method = requestMethod;
String baseString = method +
"&" +
Uri.encodeQueryComponent(
containsQueryParams == true ? url.split("?")[0] : url) +
"&" +
Uri.encodeQueryComponent(parameterString);
String signingKey = consumerSecret + "&" + token;
crypto.Hmac hmacSha1 =
crypto.Hmac(crypto.sha1, utf8.encode(signingKey)); // HMAC-SHA1
/// The Signature is used by the server to verify the
/// authenticity of the request and prevent unauthorized access.
/// Here we use HMAC-SHA1 method.
crypto.Digest signature = hmacSha1.convert(utf8.encode(baseString));
String finalSignature = base64Encode(signature.bytes);
String requestUrl = "";
if (containsQueryParams == true)
requestUrl = url.split("?")[0] +
"?" +
parameterString +
"&oauth_signature=" +
Uri.encodeQueryComponent(finalSignature);
else
requestUrl = url +
"?" +
parameterString +
"&oauth_signature=" +
Uri.encodeQueryComponent(finalSignature);
return requestUrl;
使用上面的这个函数,我可以在异步函数中发出请求,如下所示:
Future fetchWooProducts() async
http.Response response = await http.get(_getOAuthURL("GET", '$productsUrl'),
headers: "Content-Type": "Application/json");//using JWT token for WP authentication is not needed
print(response.body);
【讨论】:
非常感谢,成功了!【参考方案2】:和 QueryString 类是一样的
class QueryString
/// Parses the given query string into a Map.
static Map parse(String query)
var search = new RegExp('([^&=]+)=?([^&]*)');
var result = new Map();
// Get rid off the beginning ? in query strings.
if (query.startsWith('?')) query = query.substring(1);
// A custom decoder.
decode(String s) => Uri.decodeComponent(s.replaceAll('+', ' '));
// Go through all the matches and build the result map.
for (Match match in search.allMatches(query))
result[decode(match.group(1))] = decode(match.group(2));
return result;
【讨论】:
以上是关于Dart OAuth 1.0 - 无效签名 - 提供的签名不匹配的主要内容,如果未能解决你的问题,请参考以下文章
刷新的 OAuth2 令牌具有无效签名 (Azure AD OAuth2)
使用 Java 从 Google 请求 OAUTH 的 JWT 签名无效
OAuth 1.0 在 POSTMAN 和 PHP 代码中生成签名差异