C# 如何在.NET中使用Facebook签名的请求?

C# 如何在.NET中使用Facebook签名的请求?,c#,asp.net-mvc,facebook-javascript-sdk,asp.net-mvc-5,facebook-login,C#,Asp.net Mvc,Facebook Javascript Sdk,Asp.net Mvc 5,Facebook Login,我正在使用Facebook作为我的web应用程序(ASP.NETMVC)的登录提供商 我的登录与另一个StackOverflow帖子类似。我也分享用户的担忧 我的登录流程如下: 1.用户按下登录按钮。 2.用户必须接受该应用程序。 3.javascript回调检索响应。 返回的对象: { accessToken: "...", expiresIn: 1234, signedRequest: "...", userID:

我正在使用Facebook作为我的web应用程序(ASP.NETMVC)的登录提供商

我的登录与另一个StackOverflow帖子类似。我也分享用户的担忧

我的登录流程如下: 1.用户按下登录按钮。

2.用户必须接受该应用程序。

3.javascript回调检索响应。 返回的对象:

{
    accessToken: "...",
    expiresIn: 1234,
    signedRequest: "...",
    userID: "123456789"
}

我听说我可以使用
signed_请求
来验证用户的请求,但是所有在线示例都是针对PHP的如何在.NET中执行此操作?

是的,签名请求可用于验证传入的登录请求是否真实。如果您使用Javascript(例如,通过)登录用户,则可以使用已签名的_请求来确保数据不为假

根据,有3个主要步骤,不过我会更具体一点

  • 获取签名的_请求字符串并将其拆分为两个字符串。有一个句号字符(句号),它是一个句号。
    • 字符串的第一部分(签名)是第二部分的散列
    • 第二部分包含一些关于用户和请求的信息(用户ID、时间戳)
  • 字符串在中,但无法立即解码。
    • 它们是,这意味着
      +
      /
      字符已替换为URL友好的
      -
      字符。用
      +
      替换
      -
      字符,用
      /
      替换
      字符
    • 字符串可能没有完全填充Base64。Base64字符串应该可以被4整除;如有必要,用垫子把绳子垫起来
  • 使用应用程序机密作为密钥,使用(SHA256)哈希签名,并将结果与提供的签名进行比较。
    • 使用.NET类
  • 1.拆分和解码 代码 FixBase64String() 2.比较散列 如果
    areEqual
    true
    ,则您可以确保签名的请求有效且未被篡改(假设您的应用程序机密是安全的)


    请记住对你的应用程序保密,否则恶意用户可能会做坏事。

    要将Rowan的答案编译成最终代码:

    public static string DecodeSignedRequest(string signed_request)
    {
        try
        {
            if (signed_request.Contains("."))
            {
                string[] split = signed_request.Split('.');
    
                string signatureRaw = FixBase64String(split[0]);
                string dataRaw = FixBase64String(split[1]);
    
                // the decoded signature
                byte[] signature = Convert.FromBase64String(signatureRaw);
    
                byte[] dataBuffer = Convert.FromBase64String(dataRaw);
    
                // JSON object
                string data = Encoding.UTF8.GetString(dataBuffer);
    
                byte[] appSecretBytes = Encoding.UTF8.GetBytes(app_secret);
                System.Security.Cryptography.HMAC hmac = new System.Security.Cryptography.HMACSHA256(appSecretBytes);
                byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(split[1]));
                if (expectedHash.SequenceEqual(signature))
                {
                    return data;
                }
            }
        }
        catch
        {
            // error
        }
        return "";
    }
    
    private static string FixBase64String(string str)
    {
        while (str.Length % 4 != 0)
        {
            str = str.PadRight(str.Length + 1, '=');
        }
        return str.Replace("-", "+").Replace("_", "/");
    }
    

    谢谢罗文

    此代码有一个错误。它错误地计算了
    expectedHash
    ,因此最终的
    areEqual
    比较将失败。此行
    byte[]expectedHash=hmac.ComputeHash(Encoding.UTF8.GetBytes(dataRaw))
    需要更改为
    byte[]expectedHash=hmac.ComputeHash(Encoding.UTF8.GetBytes(split[1])
    @Rowan-我在“Facebook的工作场所”工作。在工作场所,我们也会有这个应用程序。卸载Workplace应用程序时,我能够获得已签名的\u请求。我可以使用您的方法解码有效负载以获取json对象,但我无法验证签名。
    string response = ""; // the signed_request
    
    string[] split = response.Split('.');
    
    string signatureRaw = FixBase64String(split[0]);
    string dataRaw = FixBase64String(split[1]);
    
    // the decoded signature
    byte[] signature = Convert.FromBase64String(signatureRaw);
    
    byte[] dataBuffer = Convert.FromBase64String(dataRaw);
    
    // JSON object
    string data = Encoding.UTF8.GetString(dataBuffer);
    
    static string FixBase64String(string str)
    {
        string result = str;
    
        while (result.Length % 4 != 0)
        {
            result = result.PadRight(result.Length + 1, '=');
        }
    
        result = result.Replace("-", "+").Replace("_", "/");
    
        return result;
    }
    
    byte[] appSecretBytes = Encoding.UTF8.GetBytes("my_app_secret_here");
    
    HMAC hmac = new HMACSHA256(appSecretBytes);
    
    byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(dataRaw));
    
    bool areEqual = expectedHash.SequenceEqual(signature);
    
    public static string DecodeSignedRequest(string signed_request)
    {
        try
        {
            if (signed_request.Contains("."))
            {
                string[] split = signed_request.Split('.');
    
                string signatureRaw = FixBase64String(split[0]);
                string dataRaw = FixBase64String(split[1]);
    
                // the decoded signature
                byte[] signature = Convert.FromBase64String(signatureRaw);
    
                byte[] dataBuffer = Convert.FromBase64String(dataRaw);
    
                // JSON object
                string data = Encoding.UTF8.GetString(dataBuffer);
    
                byte[] appSecretBytes = Encoding.UTF8.GetBytes(app_secret);
                System.Security.Cryptography.HMAC hmac = new System.Security.Cryptography.HMACSHA256(appSecretBytes);
                byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(split[1]));
                if (expectedHash.SequenceEqual(signature))
                {
                    return data;
                }
            }
        }
        catch
        {
            // error
        }
        return "";
    }
    
    private static string FixBase64String(string str)
    {
        while (str.Length % 4 != 0)
        {
            str = str.PadRight(str.Length + 1, '=');
        }
        return str.Replace("-", "+").Replace("_", "/");
    }