使用 C# 强制签名请求 Instagram

Enforce signed Request Instagram using C#

我正在尝试与 Instagram API 通信,并希望根据下面给出的 link link 使用签名请求与 API 进行安全通信

https://instagram.com/developer/secure-api-requests/

在默认页面,我只是获取客户端密钥、客户端密码和重定向等详细信息 URL 并通过 Instagram 进行身份验证。

一旦通过身份验证,在重定向 URL,以下是我的代码

//To Get Access Token

var json = "";

 NameValueCollection parameters = new NameValueCollection();
                parameters.Add("client_id", ConfigurationManager.AppSettings["instagram.clientid"].ToString());
                parameters.Add("client_secret", ConfigurationManager.AppSettings["instagram.clientsecret"].ToString());
                parameters.Add("grant_type", "authorization_code");
                parameters.Add("redirect_uri", ConfigurationManager.AppSettings["instagram.redirecturi"].ToString());
                parameters.Add("code", code);

                WebClient client = new WebClient();
                var result = client.UploadValues("https://api.instagram.com/oauth/access_token", "POST", parameters);
                var response = System.Text.Encoding.Default.GetString(result);

                // deserializing nested JSON string to object
                var jsResult = (JObject)JsonConvert.DeserializeObject(response);
                string accessToken = (string)jsResult["access_token"];
                int id = (int)jsResult["user"]["id"];

Page.ClientScript.RegisterStartupScript(this.GetType(), "GetToken", "<script>var instagramaccessid=\"" + @"" + id + "" + "\"; var instagramaccesstoken=\"" + @"" + accessToken + "" + "\";</script>");

获得访问令牌后,假设我从 Instagram 获得了热门照片。下面放一张div的热门照片

 <div style="clear:both;"></div>
        <div>
            <h1>
                Popular Pictures</h1>
            <div id="PopularPhotosDiv">
                <ul id="photosUL1">
                </ul>
            </div>
        </div>

然后我用下面的函数来填充div的热门照片

 <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {           
            GetPopularPhotos();

        });

function GetPopularPhotos() {
            $("#photosUL1").html("");
            $.ajax({
                type: "GET",
                async: true,
                contentType: "application/json; charset=utf-8",
                //Most popular photos
                url: "https://api.instagram.com/v1/media/popular?access_token=" + instagramaccesstoken,
                dataType: "jsonp",
                cache: false,
                beforeSend: function () {
                    $("#loading").show();
                },
                success: function (data)
                {
                    $("#loading").hide();
                    if (data == "") {
                        $("#PopularPhotosDiv").hide();
                    } else {
                        $("#PopularPhotosDiv").show();
                        for (var i = 0; i < data["data"].length; i++) {
                            $("#photosUL1").append("<li style='float:left;list-style:none;'><a target='_blank' href='" + data.data[i].link + "'><img src='" + data.data[i].images.thumbnail.url + "'></img></a></li>");
                        }

                    }
                }

            });
        }

此代码运行良好,我只想将其作为签名请求发送。

我们将不胜感激任何帮助。

Instagram API 的强制签名请求选项确保只有具有客户端密码的应用程序才能创建对 API 的请求,即使访问令牌已泄露。您为每个请求生成的签名在理论上是一个不可伪造的令牌,只有您的应用程序和 Instagram API 才能创建和验证。

为 Instagram API 创建签名的方法是使用 "keyed-hash message authentication code" (HMAC) algorithm HMAC-SHA256. In .NET, you can create HMAC-SHA256 signatures using the HMACSHA256 class。该函数需要一条将被验证的消息和用于此验证的密钥。

使用您链接到的页面上的示例,这是我在 C# 中想出的生成这些签名的方法:

static string GenerateSignature(string endpoint, Dictionary<string,string> parameters, string secret)
{
    // Build the message to be authenticated
    StringBuilder message = new StringBuilder(endpoint);
    foreach (var param in parameters.OrderBy(p => p.Key))
    {
        message.AppendFormat("|{0}={1}", param.Key, param.Value);
    }

    // Create a HMAC-SHA256 digest of the message using the secret key
    HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
    byte[] digest = hmac.ComputeHash(Encoding.UTF8.GetBytes(message.ToString()));

    // Return the digest as a hexstring to be used as a signature for the request
    return ByteArrayToString(digest);
}

static string ByteArrayToString(byte[] array)
{
    // Convert the bytes in the array to a lower-case hexstring
    return array.Aggregate(new StringBuilder(), (sb, b) => sb.Append(b.ToString("x2"))).ToString();
}

static void Main(string[] args)
{
    string secret = "6dc1787668c64c939929c17683d7cb74";
    string endpoint;
    Dictionary<string, string> parameters;
    string signature;

    // Example 1
    endpoint = "/users/self";
    parameters = new Dictionary<string, string>
    {
        { "access_token", "fb2e77d.47a0479900504cb3ab4a1f626d174d2d" },
    };
    signature = GenerateSignature(endpoint, parameters, secret);
    Console.WriteLine("sig={0}", signature);

    // Example 2
    endpoint = "/media/657988443280050001_25025320";
    parameters = new Dictionary<string, string>
    {
        { "access_token", "fb2e77d.47a0479900504cb3ab4a1f626d174d2d" },
        { "count", "10" },
    };
    signature = GenerateSignature(endpoint, parameters, secret);
    Console.WriteLine("sig={0}", signature);

    Console.ReadKey(true);
}

生成的签名应与文档示例中给出的签名相匹配。

正如 Instagram 的文档警告的那样,永远不要公开此客户端密钥。换句话说,确保客户端机密不会在移动设备、网站 JavaScript、桌面应用程序等上分发。密钥应始终在您和 Instagram 之间保密。