c#OAuth和签名

时间:2013-06-04 13:34:12

标签: c# api oauth vimeo

我正在尝试使用Vimeo API,并且在生成签名时遇到了一些问题....

基本上我有这个班级

public class OAuthParameters
{
    public string RedirectUrl { get; set; }

    public string ClientId { get; set; }
    public string ClientSecret { get; set; }

    protected string NormalizeParameters(SortedDictionary<string, string> parameters)
    {
        StringBuilder sb = new StringBuilder();

        var i = 0;
        foreach (var parameter in parameters)
        {
            if (i > 0)
                sb.Append("&");

            sb.AppendFormat("{0}={1}", parameter.Key, parameter.Value);

            i++;
        }

        return sb.ToString();
    }

    private string GenerateBase(string nonce, string timeStamp, Uri url)
    {
        var parameters = new SortedDictionary<string, string>
        {
            {"oauth_consumer_key", ClientId},
            {"oauth_signature_method", "HMAC-SHA1"},
            {"oauth_timestamp", timeStamp},
            {"oauth_nonce", nonce},
            {"oauth_version", "1.0"}
        };

        var sb = new StringBuilder();
        sb.Append("GET");
        sb.Append("&" + Uri.EscapeDataString(url.AbsoluteUri));
        sb.Append("&" + Uri.EscapeDataString(NormalizeParameters(parameters)));
        return sb.ToString();
    }

    public string GenerateSignature(string nonce, string timeStamp, Uri url)
    {
        var signatureBase = GenerateBase(nonce, timeStamp, url);
        var signatureKey = string.Format("{0}&{1}", ClientId, "");
        var hmac = new HMACSHA1(Encoding.ASCII.GetBytes(signatureKey));
        return Convert.ToBase64String(hmac.ComputeHash(new ASCIIEncoding().GetBytes(signatureBase)));
    }
}

调用它的代码在另一个类中,它有这个方法

public string GetAuthorizationUrl(string Url)
{
    var sb = new StringBuilder();
    var nonce = Guid.NewGuid().ToString();
    var timeStamp = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds.ToString();
    var signature = parameters.GenerateSignature(nonce, timeStamp, new Uri(Url));

    sb.Append(GenerateQueryStringOperator(sb.ToString()) + "oauth_consumer_key=" + Uri.EscapeDataString(parameters.ClientId));
    sb.Append("&oauth_nonce=" + Uri.EscapeDataString(nonce));
    sb.Append("&oauth_timestamp=" + Uri.EscapeDataString(timeStamp));
    sb.Append("&oauth_signature_method=" + Uri.EscapeDataString("HMAC-SHA1"));
    sb.Append("&oauth_version=" + Uri.EscapeDataString("1.0"));
    sb.Append("&oauth_signature=" + Uri.EscapeDataString(signature));

    return Url + sb.ToString();
}

private string GenerateQueryStringOperator(string currentUrl)
{
    if (currentUrl.Contains("?"))
        return "&";
    else
        return "?";
}

我传递的Url(获取我的身份验证令牌)是https://vimeo.com/oauth/request_token,但每当我打电话给我时,我都会收到错误消息

401 Unauthorized - Invalid signature - The oauth_signature passed was not valid.

这让我疯了。我看不出可能导致这个问题的原因。

如果有人能给我一些帮助,那就太棒了。

更新1

有人说使用Uri.EscapeDataString不是编码我的字符串的正确方法。我在移动EscapeDataString之前使用了这个函数:

    protected string UrlEncode(string unencodedString)
    {
        var encodedString = new StringBuilder();
        var unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";

        foreach (char symbol in unencodedString)
            if (unreservedChars.IndexOf(symbol) != -1)
                encodedString.Append(symbol);
            else
                encodedString.Append('%' + String.Format("{0:X2}", (int)symbol));

        return encodedString.ToString();
    }

但这仍然无济于事。同样使用http://hueniverse.com/oauth/guide/authentication/并没有提供任何有关导致我的问题的见解:(

更新2

所以,我通过hueniverse运行代码,发现我的时间戳不准确(它有小数位)所以我改变了使用这个函数生成时间戳的方式:

    public string GenerateTimeStamp()
    {
        TimeSpan ts = DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0));
        string timeStamp = ts.TotalSeconds.ToString();
        timeStamp = timeStamp.Substring(0, timeStamp.IndexOf("."));
        return timeStamp;
    }

所以现在当我看到我的基本签名时,我得到了:

POST&https%3A%2F%2Fvimeo.com%2Foauth%2Frequest_token%2F&oauth_consumer_key%3Dmykey%26oauth_nonce%3D66c80d6b-9ff6-404b-981b-56f40f356a31%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1370444366%26oauth_token%3D%26oauth_version%3D1.0

如果我将它与hueniverse生成的那个进行比较,它会生成:

POST&https%3A%2F%2Fvimeo.com%2Foauth%2Frequest_token%2F&oauth_consumer_key%3Dmykey%26oauth_nonce%3D00b81872-688b-4184-a978-206e5fbcc531%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1370446860%26oauth_token%3D%26oauth_version%3D1.0

如果生成的字符串的长度是任何东西,那么它们是准确的。我的下一个测试是创建完全相同的时间戳,并查看它们是否生成相同的签名....

3 个答案:

答案 0 :(得分:0)

Uri.EscapeDataString的文档声明它默认使用RFC 2396(除非启用了IRI或IDN解析)。

OAuth 1.0要求您使用RFC 3986对您的值进行编码。

我建议您针对Hueniverse Guide测试输出。它是调试oauth签名的一个非常有用的工具,应该比执行实际的API请求快得多。

答案 1 :(得分:0)

在上面的代码中设置timeStamp:

var timeStamp = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds.ToString();

您将获得一个十进制时间戳,这将使您的authorizedUrl无法正常工作

如果你在将结果转换为字符串之前截断结果,这将有效。

var timeStamp = Math.Truncate((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds).ToString();

答案 2 :(得分:0)

代码的问题在这里。

GenerateSignature函数中,您设置变量:

var signatureKey = string.Format("{0}&{1}", ClientId, "");

这应该是:

var signatureKey = string.Format("{0}&{1}", ClientSecret , "");