Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在dart中生成oauth签名_Dart_Flutter - Fatal编程技术网

如何在dart中生成oauth签名

如何在dart中生成oauth签名,dart,flutter,Dart,Flutter,我正在使用flifter开发一个健身应用程序。我正在尝试使用Fatsecret API用于食品和配方数据库 一般来说,我不熟悉flutter和API(以前是初级android开发人员,只与firebase合作)。现在我一直在为fatsecret API生成OAuth签名 签名生成的秘密,但我不明白 这是我的密码 import 'dart:convert'; import 'package:convert/convert.dart'; import 'package:crypto/crypto.

我正在使用flifter开发一个健身应用程序。我正在尝试使用Fatsecret API用于食品和配方数据库

一般来说,我不熟悉flutter和API(以前是初级android开发人员,只与firebase合作)。现在我一直在为fatsecret API生成OAuth签名

签名生成的秘密,但我不明白

这是我的密码

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;
}
我是否以错误的方式创建签名?或者有人能看出我错在哪里吗

谢谢大家!

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);
  }
}
导入'dart:async';
导入“dart:convert”;
导入“dart:math”;
将“package:http/http.dart”导入为http;
导入“package:convert/convert.dart”;
导入“包:crypto/crypto.dart”;
//TwitterApi类改编自DanTup:
// https://blog.dantup.com/2017/01/simplest-dart-code-to-post-a-tweet-using-oauth/
类脂肪分泌{
最后一个字符串fatsecretapbaseurl=“platform.fatsecret.com”;
bool-isJson=true;
最终字符串consumerKey、ConsumerKeyCret、accessToken、accessTokenSecret;
Hmac_Sigasher;
FatSecretApi(this.consumerKey,this.ConsumerKeyCret,this.accessToken,
这是我的秘密){
var bytes=utf8.encode($consumerKeySecret&$accessTokenSecret);
_sigHasher=新的Hmac(sha1,字节);
}
FatSecretApi forceXml(){
this.isJson=false;
归还这个;
}
///发送带有所提供文本的tweet,并从twitterapi返回响应。
未来请求(地图数据){
if(isJson){
数据[“格式”]=“json”;
}
返回_callGetApi(“rest/server.api”,data);
}
Future\u callGetApi(字符串url、地图数据){
Uri requestUrl=Uri.https(fatSecretApiBaseUrl,url);
打印(数据[“方法]);
_setAuthParams(“GET”,requestUrl.toString(),data);
requestUrl=Uri.https(requestUrl.authority、requestUrl.path、data);
字符串oAuthHeader=\u GenerateAuthHeader(数据);
//从数据构建OAuth HTTP头。
//构建表单数据(排除已经在标题中的OAuth内容)。
//var formData=_filterMap(数据,(k)=>!k.startsWith(“oauth”);
返回_sendGetRequest(requestUrl,oAuthHeader);
}
void\u setAuthParams(字符串请求方法、字符串url、映射数据){
//自1970年1月1日起,时间戳以秒为单位。
//var timestamp=new DateTime.now().toUtc().difference(_epochUtc).unseconds;
var millissecondssinceepoch=new DateTime.now().toUtc().millissecondssinceepoch;
var timestamp=(毫秒nceepoch/100).round();
//添加构造哈希时需要使用的所有OAuth头。
数据[“oauth_消费者密钥”]=消费者密钥;
数据[“oauth_签名_方法”]=“HMAC-SHA1”;
数据[“oauth_timestamp”]=timestamp.toString();
data[“oauth\u nonce”]=\u randomString(8);//必需,但Twitter似乎没有使用它
if(accessToken!=null&&accessToken.isNotEmpty)数据[“oauth_token”]=accessToken;
数据[“oauth_版本”]=“1.0”;
//生成OAuth签名并将其添加到我们的有效负载中。
数据[“oauth_签名”]=“生成签名(requestMethod,Uri.parse(url),data);
}
///从OAuth头值生成OAuth签名。
String _generateSignature(String requestMethod、Uri url、映射数据){
var sigString=_toQueryString(数据);
var fullSigData=“$requestMethod&${u encode(url.toString())}&${u encode(sigString)}”;
返回base64.encode(_hash(fullSigData));
}
///从值(包括签名)生成原始OAuth HTML头。
字符串_GenerateAuthHeader(地图数据){
var oauthHeaderValues=_filterMap(数据,(k)=>k.startsWith(“oauth”);
返回“OAuth”+_toauthHeader(oauthHeaderValues);
}
///发送HTTP请求并返回响应。
Future\u sendGetRequest(Uri fullUrl,字符串oAuthHeader)异步{
return wait http.get(fullUrl,头:{});
}
映射过滤器映射(
地图,布尔测试(字符串键)){
返回新的Map.fromIterable(Map.keys.where(test),值:(k)=>Map[k]);
}
字符串\u到查询字符串(地图数据){
var items=data.keys.map((k)=>“$k=${{u encode(data[k])}”).toList();
items.sort();
返回项目。加入(“&”);
}
字符串ToAuthHeader(地图数据){
var items=data.keys.map((k)=>“$k=\”${u encode(data[k])}\”).toList();
items.sort();
返回项目。加入(“,”);
}
List(hash(String data)=>_sigHasher.convert(data.codeUnits).字节;;
字符串编码(字符串数据)=>percent.encode(数据.codeUnits);
字符串_随机字符串(整数长度){
var rand=new Random();
var codeUnits=new List.generate(
长度,
(索引){
返回兰特nextInt(26)+97;
}
);
返回新字符串.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:async';
导入“dart:convert”;
导入“包:颤振测试应用程序/错误/FatSecretException.dart”;
导入“包:颤振测试应用程序/模型/dayNutrientsEntry.dart”;
导入“包:颤振测试应用程序/网络/fatSecretApi.dart”;
导入“包:颤振测试应用程序/模型/食品测试程序”;
导入“package:flatter\u test\u app/model/auth/user\u fat\u secret\u auth\u model.dart”;
类RestClient{
//如果没有,请从fatSecret API生成
字符串消费主义;
//如果没有,请从fatSecret API生成
字符串消费信贷;
//创建一个新的RestClient实例。
//尽量使单例也避免多个实例
//确保设置AppConfig使用者密钥和机密。
RestClient(){
this.consumerKey='CONSUMER_KEY';
this.consumerKeySecret='CONSUMER\u KEY\u SECRET';
}
/*
*向fatSecret API上的“food.search”方法发送API调用
*该方法输入查询字符串以在食物中搜索
*返回类型[SearchFoodItem]
*请参考模型包。
*/
Future searchFood(字符串查询)异步{
列表=[];
//FatSecretApi发送电话之前,请确保设置了消费者密钥
FatSecretApi foodSearch=FatSecretApi(
这是消费市场,
这是康瑟姆
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;
  }
}