- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 flutter 开发健身应用程序。我正在尝试将 Fatsecret API 用于食品和食谱数据库。
我一般是 flutter 和 API 的新手(以前作为初级 android 开发人员,只使用过 firebase)。现在我被困在为 fatsecret API 生成 OAuth 签名。
Fatsecret documentation对于签名生成,但我不明白。
这是我的代码
import 'dart:convert';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;
import 'package:random_string/random_string.dart';
import 'package:sortedmap/sortedmap.dart';
// FatSecret API
class FsApiService {
/// I used these tuts for reference
// https://blog.dantup.com/2017/01/simplest-dart-code-to-post-a-tweet-
// using-oauth/
// http://platform.fatsecret.com/api/Default.aspx?screen=rapiauth
// https://github.com/EugeneHoran/Android-FatSecret-REST-API
// https://stackoverflow.com/questions/49797558/how-to-make-http-post-
// request-with-url-encoded-body-in-flutter
//https://groups.google.com/a/dartlang.org/forum/#!topic/cloud/Ci1gFhYBSDQ
// https://stackoverflow.com/questions/28910178/calculating-an-oauth-
// signature
static const API_KEY = 'c8f3e40ed0634f5e99919eb944892b17';
static const SHARED_SECRET = 'e8a682cd53094edb9d09090245371ba5';
static const APP_METHOD = 'POST';
static const REQUEST_URL =
'http://platform.fatsecret.com/rest/server.api';
static const SIGNATURE_METHOD = 'HMAC-SHA1';
static const OAUTH_VERSION = '1.0';
var _sigHasher;
FsApiService() {
var bytes = utf8.encode('$SHARED_SECRET&');
_sigHasher = new Hmac(sha1, bytes);
}
/// Fetches all foods from Fatsecret Api
fetchAllFoodsFromApi() async {
Map<String, String> params = {
'oauth_consumer_key': API_KEY,
'oauth_signature_method': SIGNATURE_METHOD,
'oauth_timestamp':
(DateTime.now().millisecondsSinceEpoch).toString(),
'oauth_nonce': nounce(),
'oauth_version': (1.0).toString(),
'format': 'json',
'method': 'foods.search',
'search_expression': 'cheese'
};
var signatureUri = _generateSignature(APP_METHOD, REQUEST_URL, params);
params['oauth_signature'] = signatureUri;
var sortedParams = SortedMap.from(params);
var client = http.Client();
final response = await client.post(
REQUEST_URL,
headers: sortedParams,
);
print(response.statusCode);
print(response.body);
print('$signatureUri');
print('$sortedParams');
print('$params');
}
String nonce() {
return randomString(8);
}
String _generateSignature(
String method, String baseUrl, Map<String, String> params) {
var encodedMethod = Uri.encodeComponent(method);
var encodedUrl = Uri.encodeComponent(baseUrl);
var sortedParams = SortedMap.from(params);
var concatedParams = _toQueryString(sortedParams);
var encodedParams = Uri.encodeComponent(concatedParams);
var finalUrl = '$encodedMethod&${_encode(encodedUrl.toString())}'
+ '&${_encode(encodedParams)}';
var base64converted = base64.encode(_hash(finalUrl));
print('encoded method = $encodedMethod');
print('encoded url = $encodedUrl');
print('encoded params = $encodedParams');
print('final url = $finalUrl');
print('base64converted = $base64converted');
return base64converted;
}
String _toQueryString(Map<String, String> data) {
var items = data.keys.map((k) => "$k=${_encode(data[k])}").toList();
items.sort();
return items.join('&');
}
String _encode(String data) {
return percent.encode(data.codeUnits);
}
List<int> _hash(String data) => _sigHasher.convert(data.codeUnits).bytes;
}
2018-11-01 19:53:17.681 25882-25907/com.enkefa.ninjaapp I/flutter: 200
2018-11-01 19:53:17.735 25882-25907/com.enkefa.ninjaapp I/flutter: <?xml
version="1.0" encoding="utf-8" ?>
<error xmlns="http://platform.fatsecret.com/api/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://platform.fatsecret.com/api/1.0/
http://platform.fatsecret.com/api/1.0/fatsecret.xsd">
<code>2</code>
<message>Missing required oauth parameter:
oauth_signature_method</message>
</error>
最佳答案
API类
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:http/http.dart' as http;
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
// TwitterApi class adapted from DanTup:
// https://blog.dantup.com/2017/01/simplest-dart-code-to-post-a-tweet-using-oauth/
class FatSecretApi {
final String fatSecretApiBaseUrl = "platform.fatsecret.com";
bool isJson = true;
final String consumerKey, consumerKeySecret, accessToken, accessTokenSecret;
Hmac _sigHasher;
FatSecretApi(this.consumerKey, this.consumerKeySecret, this.accessToken,
this.accessTokenSecret) {
var bytes = utf8.encode("$consumerKeySecret&$accessTokenSecret");
_sigHasher = new Hmac(sha1, bytes);
}
FatSecretApi forceXml() {
this.isJson = false;
return this;
}
/// Sends a tweet with the supplied text and returns the response from the Twitter API.
Future<http.Response> request(Map<String, String> data) {
if (isJson) {
data["format"] = "json";
}
return _callGetApi("rest/server.api", data);
}
Future<http.Response> _callGetApi(String url, Map<String, String> data) {
Uri requestUrl = Uri.https(fatSecretApiBaseUrl, url);
print(data["method"]);
_setAuthParams("GET", requestUrl.toString(), data);
requestUrl = Uri.https(requestUrl.authority, requestUrl.path, data);
String oAuthHeader = _generateOAuthHeader(data);
// Build the OAuth HTTP Header from the data.
// Build the form data (exclude OAuth stuff that's already in the header).
// var formData = _filterMap(data, (k) => !k.startsWith("oauth_"));
return _sendGetRequest(requestUrl, oAuthHeader);
}
void _setAuthParams(String requestMethod, String url, Map<String, String> data) {
// Timestamps are in seconds since 1/1/1970.
// var timestamp = new DateTime.now().toUtc().difference(_epochUtc).inSeconds;
var millisecondsSinceEpoch = new DateTime.now().toUtc().millisecondsSinceEpoch;
var timestamp = (millisecondsSinceEpoch / 100).round();
// Add all the OAuth headers we'll need to use when constructing the hash.
data["oauth_consumer_key"] = consumerKey;
data["oauth_signature_method"] = "HMAC-SHA1";
data["oauth_timestamp"] = timestamp.toString();
data["oauth_nonce"] = _randomString(8); // Required, but Twitter doesn't appear to use it
if (accessToken != null && accessToken.isNotEmpty) data["oauth_token"] = accessToken;
data["oauth_version"] = "1.0";
// Generate the OAuth signature and add it to our payload.
data["oauth_signature"] = _generateSignature(requestMethod, Uri.parse(url), data);
}
/// Generate an OAuth signature from OAuth header values.
String _generateSignature(String requestMethod, Uri url, Map<String, String> data) {
var sigString = _toQueryString(data);
var fullSigData = "$requestMethod&${_encode(url.toString())}&${_encode(sigString)}";
return base64.encode(_hash(fullSigData));
}
/// Generate the raw OAuth HTML header from the values (including signature).
String _generateOAuthHeader(Map<String, String> data) {
var oauthHeaderValues = _filterMap(data, (k) => k.startsWith("oauth_"));
return "OAuth " + _toOAuthHeader(oauthHeaderValues);
}
/// Send HTTP Request and return the response.
Future<http.Response> _sendGetRequest(Uri fullUrl, String oAuthHeader) async {
return await http.get(fullUrl, headers: { });
}
Map<String, String> _filterMap(
Map<String, String> map, bool test(String key)) {
return new Map.fromIterable(map.keys.where(test), value: (k) => map[k]);
}
String _toQueryString(Map<String, String> data) {
var items = data.keys.map((k) => "$k=${_encode(data[k])}").toList();
items.sort();
return items.join("&");
}
String _toOAuthHeader(Map<String, String> data) {
var items = data.keys.map((k) => "$k=\"${_encode(data[k])}\"").toList();
items.sort();
return items.join(", ");
}
List<int> _hash(String data) => _sigHasher.convert(data.codeUnits).bytes;
String _encode(String data) => percent.encode(data.codeUnits);
String _randomString(int length) {
var rand = new Random();
var codeUnits = new List.generate(
length,
(index){
return rand.nextInt(26)+97;
}
);
return new String.fromCharCodes(codeUnits);
}
}
import 'dart:async';
import 'dart:convert';
import 'package:flutter_test_app/error/FatSecretException.dart';
import 'package:flutter_test_app/model/dayNutrientsEntry.dart';
import 'package:flutter_test_app/network/fatSecretApi.dart';
import 'package:flutter_test_app/model/foodItem.dart';
import 'package:flutter_test_app/model/auth/user_fat_secret_auth_model.dart';
class RestClient {
// if you don't have one, generate from fatSecret API
String consumerKey;
// if you don't have one, generate from fatSecret API
String consumerKeySecret;
// creates a new RestClient instance.
// try to make singleton too avoid multiple instances
// make sure to set AppConfig consumer keys and secrets.
RestClient() {
this.consumerKey = 'CONSUMER_KEY';
this.consumerKeySecret = 'CONSUMER_KEY_SECRET';
}
/*
* Sends an API call to "food.search" method on fatSecret APi
* the method inputs a query string to search in food
* Return Type [SearchFoodItem]
* please refer to model package.
*/
Future<List<SearchFoodItem>> searchFood(String query) async {
List<SearchFoodItem> list = [];
// FatSecretApi be sure that consumer keys are set before you send a call
FatSecretApi foodSearch = FatSecretApi(
this.consumerKey,
this.consumerKeySecret,
"",
"",
);
var result = await foodSearch
.request({"search_expression": query, "method": "foods.search"})
.then((res) => res.body)
.then(json.decode)
.then((json) => json["foods"])
.then((json) => json["food"])
.catchError((err) {
print(err);
});
// Create a POJO class and parse it
result.forEach((foodItem) => list.add(SearchFoodItem.fromJson(foodItem)));
return list;
}
/*
* Sends an API call to "profile.create" method on fatSecret APi
* the method inputs unique user Id
* Return Type [Map]
* please refer to fatSecret return types
*/
Future<Map> createProfile(String userId) async {
// Be sure that consumer keys are set before you send a call
FatSecretApi api = FatSecretApi(this.consumerKey, this.consumerKeySecret, "", "");
var response =
api.request({"method": "profile.create", "user_id": userId});
var jsonBody = await response.then((res) => res.body).then(json.decode);
if (jsonBody["error"] != null) {
var errorMap = jsonBody["error"];
throw FatSecretException(errorMap["code"], errorMap["message"]);
}
var profile = jsonBody["profile"];
return profile;
}
/*
* Sends an API call to "profile.get_auth" method on fatSecret APi
* the method inputs unique user Id
* Return Type [Map]
* please refer to fatSecret return types
*/
Future<Map> getProfileAuth(String userId) async {
//var session = await Preferences().getUserSession();
var api =
new FatSecretApi(this.consumerKey, this.consumerKeySecret, "", "");
var jsonBody = await api
.request({"method": "profile.get_auth", "user_id": userId})
.then((res) => res.body)
.then(json.decode);
// .then((json) => json["profile"]);
if (jsonBody["error"] != null) {
var errorMap = jsonBody["error"];
throw new FatSecretException(errorMap["code"], errorMap["message"]);
}
var profile = jsonBody["profile"];
return profile;
}
/*
* Sends an API call to "food_entries.get_month" method on fatSecret APi
* the method inputs [Date] and [UserFatSecretAuthModel] optional
* if you want to access some other user you can set UserFatSecretAuthModel in parameters
* Return Type [DayNutrientsEntry]
* please refer to model package
*/
Future<List<DayNutrientsEntry>> getMonthFoodEntries(
{String date, UserFatSecretAuthModel user}) async {
if (user == null) {
// set user if you have already stored user in preferences
// var user = await Preferences().getUserSession();
}
List<DayNutrientsEntry> list = [];
var api = new FatSecretApi(this.consumerKey, this.consumerKeySecret,
user?.authToken, user?.authSecret);
Map<String, String> params = {"method": "food_entries.get_month"};
if (date != null && date.isNotEmpty) params["date"] = date;
try {
var r = await api
.request(params)
.then((res) => res.body)
.then(json.decode)
.then((json) => json["month"])
.then((json) => json["day"]);
if (r is List) {
r.forEach((foodItem) => list.add(DayNutrientsEntry.fromJson(foodItem)));
} else {
list.add(DayNutrientsEntry.fromJson(r));
}
} catch (e) {}
return list;
}
}
关于dart - 如何在 dart 中生成 oauth 签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53104511/
我有一个相当冗长的命令行程序,它需要用户输入参数,然后使用这些参数进行处理。我想做的是将程序拆分为交互式和非交互式。我试图这样做,并打算让非交互式程序“调用”交互式程序并使用结果(参数),基于这些参数
谁能解释为什么我们在构造函数的参数中使用大括号。 class Cars { String carName; bool isAuto; // create the constructor
我想知道是否有Dart函数,例如PHP的 strrev()。如果没有,您能否请向我展示任何源代码如何自行实现? 谢谢。 最佳答案 我还没有在API中找到一个新的Dart用户(截至今天下午)。但是,以任
我有一个组件,我想根据一个 bool 值绑定(bind)一个不同的 css 类。我的组件代码中有以下内容: bindCssClass(div, "open", this, "task.isOpen")
我一直在研究如何在dart中播放.wav文件,并且已经能够通过dart:html库中定义的AudioElement成功完成此操作。但是,我对使用dart:web_audio库感兴趣,并且遇到了所有这些
Dart 是否旨在实现许多与 Haxe 相同的功能,以便能够针对其他语言和运行时?它是语言和工具的既定目标还是已知目标? 最佳答案 不。Dart 专门针对 web 应用程序开发(更具体地说,客户端 w
我正在尝试让 dart 正常工作。作为编辑器,我想使用 emacs dart-mode。我有两个关于在没有 dart 编辑器的情况下使用 dart 的问题: 1) 我是否需要手动调用 dart2js,
我正在使用列表来创建墨水瓶按钮。我想将列表放在一个单独的 dart 文件中,并将该文件导入到我使用列表的文件中。我不知道如何导入列表。 https://pastebin.com/mf0kvsGu 我制
我正在编写一个 flutter 应用程序,它通过蓝牙 (FlutterBlue) 向设备发送命令。该设备控制一些 LED。通信总体上运行良好,但是:在用户界面上,我有一个控制光强度的 slider 。
我正在使用来自 Get started: command-line and server apps | Dart 的说明.运行 dart --version 时,我得到: Dart VM versio
var c 返回 3 但 10/7=1.4285,其余为 0.4285,operator % 有错误? void main() { var a = 10; var b = 7; var c
如文档中所述: The const keyword isn’t just for declaring constant variables. You can also use it to create
在 Dart 中,我如何最好地编写相当于(不可变/值/非对象) 的代码输出或引用参数 ? 例如在 C#-ish 中,我可能会编码: function void example() { int re
Dart 支持的多重继承机制有哪些? 最佳答案 不,Dart 不支持多重实现继承。 Dart 具有接口(interface),并且与大多数其他类似语言一样,它具有多个接口(interface)继承。
我正在寻找有关如何制作可以采用位置子参数的 web 组件的资源。就像是: {{value}} // this could be any uneditable element {{value}
使用polymer.dart 的Dart 应用程序的pubspec.yaml 文件如下所示(来自Polymer.dart Code Lab): name: polymer_and_dart descr
今天我决定开始学习 Dart 语言,我从 Tour 开始,那里有一个例子: // These work in a const string. const aConstNum = 0; const aC
我正在查找字符串类和其他一些资源,试图了解如何格式化字符串。首先,我试图将数字填充到字符串中,但不是精度。 例子: int a = 0, b = 5, c = 15, d = 46; String
我知道的大部分是Javascript。我相信“列表”是 Dart 最接近数组的东西,但它们在技术上是一样的吗?将它们视为数组是错误的吗?同样, map 会被视为对象吗?我意识到可能存在差异,但进行这种
现在,白色背景刺痛了我的眼睛,因为这是一个looong的黑夜。是否可以从 Dart 编辑器 (v 0.1) 更改主题(更改为更暗的主题)?选择背景颜色和语法高亮怎么样? 最佳答案 是的,这是可能的,我
我是一名优秀的程序员,十分优秀!