抖音商家自研
源码基于抖店开放平台源码修改,因为用的VS版本比较老,所以很多地方做了调整,再加上自己的代码
public class douyin
{
public static string appkey = "*******";//换成自己的appkey
public static string appSecret = "*******************";//换成自己的appSecret
public static string host = "https://openapi-fxg.jinritemai.com";
public string Token = "";
public douyin(string shopId, string shopName)
{
//获取当前Token;
Token = GetToken(shopId, shopName);
}
public void GetSoldsByTime(string shopId, DateTime stateTime, DateTime endTime)
{
string method = "order.searchList";
long timestamp = GetTimeStamp(DateTime.Now);
long startTimeStamp = GetTimeStamp(stateTime);
long endTimeStamp = GetTimeStamp(endTime);
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("page", 1);
dic.Add("size", 100);//最大支持100
dic.Add("create_time_start", startTimeStamp);
dic.Add("create_time_end", endTimeStamp);//测试账号需要 test_shop = "1"
// 序列化参数
var paramJson = Marshal(dic);
// 计算签名
var sign = Sign(appkey, appSecret, method, timestamp, paramJson);
string msg = Fetch(method, timestamp.ToString(), paramJson, Token, sign);
}
public string GetToken(string shopId, string shopName)
{
TB_Login_Number tokenInfo = new TB_Login_Number();
//根据shopId 判断当前数据库是否有存储Token
//这里从数据库根据ShopId查询当前Token存不存在
if (tokenInfo == null || string.IsNullOrWhiteSpace(tokenInfo.access_token))
{
//当Token不存在时,创建Token并存储
TokenResult token = CreateToken(shopId);
if (token != null)
{
//这里可以存储Token到自己的数据库保存
return token.access_token;
}
return "";
}
//Token存在时判断Token是否即将过期或者已过期
var timespan = (tokenInfo.CTime.AddSeconds(Convert.ToInt32(tokenInfo.expires_in)) - DateTime.Now).TotalHours;
if (timespan < 1)
{
var token = RefreshToken(tokenInfo.refresh_token);
if (token != null)
{
//刷新Token 之后修改数据库Token
return token.access_token;
}
return "";
}
return tokenInfo.access_token;
}
public TokenResult CreateToken(string shopId)
{
var method = "token.create";
long timestamp = GetTimeStamp(DateTime.Now);
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("shop_id", shopId);
dic.Add("code", "");
dic.Add("grant_type", "authorization_self");
dic.Add("test_shop", "1");//测试账号需要 test_shop = "1"
// 序列化参数
var paramJson = Marshal(dic);
// 计算签名
var sign = Sign(appkey, appSecret, method, timestamp, paramJson);
var methodPath = method.Replace('.', '/');
var url = host + "/" + methodPath +
"?method=" + HttpUtility.UrlEncode(method, Encoding.UTF8) +
"&app_key=" + HttpUtility.UrlEncode(appkey, Encoding.UTF8) +
"×tamp=" + HttpUtility.UrlEncode(timestamp.ToString(), Encoding.UTF8) +
"&v=" + HttpUtility.UrlEncode("2", Encoding.UTF8) +
"&sign=" + HttpUtility.UrlEncode(sign, Encoding.UTF8) +
"&sign_method=" + HttpUtility.UrlEncode("hmac-sha256", Encoding.UTF8);
var msg = HttpPost(url, paramJson);
JObject job = JObject.Parse(msg);
if (job.Value<int>("code") == 10000)
{
return JsonConvert.DeserializeObject<TokenResult>(job["data"].ToString());
}
return null;
}
public TokenResult RefreshToken(string refreshToken)
{
var method = "token.refresh";
long timestamp = GetTimeStamp(DateTime.Now);
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("refresh_token", refreshToken);
dic.Add("grant_type", "refresh_token");
// 序列化参数
var paramJson = Marshal(dic);
// 计算签名
var sign = Sign(appkey, appSecret, method, timestamp, paramJson);
var methodPath = method.Replace('.', '/');
var url = host + "/" + methodPath +
"?method=" + HttpUtility.UrlEncode(method, Encoding.UTF8) +
"&app_key=" + HttpUtility.UrlEncode(appkey, Encoding.UTF8) +
"×tamp=" + HttpUtility.UrlEncode(timestamp.ToString(), Encoding.UTF8) +
"&v=" + HttpUtility.UrlEncode("2", Encoding.UTF8) +
"&sign=" + HttpUtility.UrlEncode(sign, Encoding.UTF8) +
"&sign_method=" + HttpUtility.UrlEncode("hmac-sha256", Encoding.UTF8);
var msg = HttpPost(url, paramJson);
JObject job = JObject.Parse(msg);
if (job.Value<int>("code") == 10000)
{
return JsonConvert.DeserializeObject<TokenResult>(job["data"].ToString());
}
return null;
}
// 调用Open Api,取回数据
public string Fetch(string method, string timestamp, string paramJson,
string accessToken, string sign)
{
var methodPath = method.Replace('.', '/');
var url = host + "/" + methodPath +
"?method=" + HttpUtility.UrlEncode(method, Encoding.UTF8) +
"&app_key=" + HttpUtility.UrlEncode(appkey, Encoding.UTF8) +
"&access_token=" + HttpUtility.UrlEncode(accessToken, Encoding.UTF8) +
"×tamp=" + HttpUtility.UrlEncode(timestamp.ToString(), Encoding.UTF8) +
"&v=" + HttpUtility.UrlEncode("2", Encoding.UTF8) +
"&sign=" + HttpUtility.UrlEncode(sign, Encoding.UTF8) +
"&sign_method=" + HttpUtility.UrlEncode("hmac-sha256", Encoding.UTF8);
var msg = HttpPost(url, paramJson);
return msg;
}
private string HttpPost(string url, string paramJson)
{
var context = Encoding.UTF8.GetBytes(paramJson);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Method = "POST";
//request.Headers.Add("Accept", "*/*");
request.ContentType = "application/json;charset=UTF-8";
var s = request.GetRequestStream();
s.Write(context, 0, context.Length);
var response = (HttpWebResponse)request.GetResponse();
var stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
return reader.ReadToEnd();
}
/// <summary>
/// DateTime时间格式转换为Unix时间戳格式
/// </summary>
/// <returns></returns>
private long GetTimeStamp(DateTime time)
{
// DateTime时间格式转换为Unix时间戳格式
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
return (long)(DateTime.Now - startTime).TotalSeconds;
}
// 计算签名
private string Sign(string appKey, string appSecret, string method, long timestamp, string paramJson)
{
// 按给定规则拼接参数
var paramPattern = "app_key" + appKey + "method" + method + "param_json" + paramJson + "timestamp" +
timestamp + "v2";
var signPattern = appSecret + paramPattern + appSecret;
Console.WriteLine("sign_pattern:" + signPattern);
return Hmac(signPattern, appSecret);
}
// 计算hmac
private string Hmac(string plainText, string appSecret)
{
var h = new HMACSHA256(Encoding.UTF8.GetBytes(appSecret));
var sum = h.ComputeHash(Encoding.UTF8.GetBytes(plainText));
var sb = new StringBuilder();
foreach (byte b in sum)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
// 序列化参数
// 这一步看上去冗余,实际很重要。如果要自己实现,则必须保证这三点:
// 1、保证JSON所有层级上Key的有序性
// 2、保证JSON的所有数值不带多余的小数点
// 3、保证转义逻辑与这段代码一致
private static string Marshal(Dictionary<string, object> obj)
{
// 第一步:把字典按Key的字母顺序排序
IDictionary<string, object> sortedParams = new SortedDictionary<string, object>(obj, StringComparer.Ordinal);
return JsonConvert.SerializeObject(sortedParams);
}
}

浙公网安备 33010602011771号