Facebook:获取会话密钥时获取不正确的签名 (104)

Posted

技术标签:

【中文标题】Facebook:获取会话密钥时获取不正确的签名 (104)【英文标题】:Facebook: Getting Incorrect Signature (104) when Getting Session Key 【发布时间】:2010-11-27 09:50:30 【问题描述】:

我正在尝试使用HttpClient 库(以调用 Facebook API 的 REST 端点)来获取会话密钥并验证用户...

我的代码在这里:

RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations =
 "classpath*:**/*applicationContext-test.xml" )
public class FacebookUserTest

    final String API_KEY = "9e2568d68f182a2957878f3acedd9453";
    final String SECRET = "f1298956895d39110be92a672e0d2284";
    final String TOKEN = "aa0c41aa4532053e8d0097844ab9bc7d";
    final String LOGIN = "http://www.facebook.com/login.php";
    final String HOST = "http://www.facebook.com/restserver.php";

    private static Logger log = 
        LoggerFactory.getLogger(FacebookUserTest.class);

    protected FacebookUser FacebookUser;

    @Test
    public void testFindUserBySessionKey() throws Exception
    
        loginToFacebook();
        String sessionKey = getSessionKey();
    

    public void loginToFacebook() throws Exception
    
        HttpClient client = new HttpClient();
        client.setParams(new HttpClientParams());
        client.setState(new HttpState());

        GetMethod get = new GetMethod(LOGIN + "?api_key=" + API_KEY
            + "&v=1.0&auth_token=" + TOKEN);

        // Get login screen
        client.executeMethod(get);

        // Post credentials to login
        PostMethod post = new PostMethod(LOGIN);
        post.addParameter(new NameValuePair("api_key", API_KEY));
        post.addParameter(new NameValuePair("v", "1.0"));
        post.addParameter(new NameValuePair("auth_token", TOKEN));
        post.addParameter(new NameValuePair("email", "user@email.com"));
        post.addParameter(new NameValuePair("pass", "password"));
        client.executeMethod(post);
    

    public String getSessionKey() throws Exception
    
        HttpClient client = new HttpClient();

        // Obtain session key
        String host = "http://www.facebook.com/restserver.php";
        String sessSecret = "false";
        String toMd = "api_key=" + API_KEY + "auth_token=" + TOKEN
            + "format=xmlgenerate_session_secret=" + sessSecret
            + "method=facebook.auth.getSessionv=1.0" + SECRET;
         String md5 = Md5Utils.MD5(toMd);

         PostMethod post = new PostMethod(HOST);

         NameValuePair[] data = 
            new NameValuePair("api_key", API_KEY),
            new NameValuePair("auth_token", TOKEN),
            new NameValuePair("format", "xml"),
            new NameValuePair("generate_session_secret", SECRET),
            new NameValuePair("method", "auth.getSession"),
            new NameValuePair("sig", md5), new NameValuePair("v", "1.0")
         ;

         post.setRequestBody(data);
         post.setRequestHeader("Content-Type",
            "application/x-www-form-urlencoded");
         post.setRequestHeader("User-Agent",
            "Facebook API PHP5 Client 1.1 (curl) 5");

         // execute method and handle any error responses.
         client.executeMethod(post);

         StringBuilder sb = new StringBuilder();
         byte[] b = new byte[4096];

         for (int n; (n = post.getResponseBodyAsStream().read(b)) != -1;) 
         
             sb.append(new String(b, 0, n));
         

         String sessionId = sb.toString();
         log.warn("Session Id: " + sessionId);

         return sessionId;
     

当我运行 JUnit 测试时,这是从控制台打印的内容:

WARN : com.myapp.FacebookUserTest - Session Id: 

<?xml version="1.0" encoding="UTF-8"?>
<error_response xmlns="http://api.facebook.com/1.0/" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://api.facebook.com/1.0/
   http://api.facebook.com/1.0/facebook.xsd">
    <error_code>104</error_code>
    <error_msg>Incorrect signature</error_msg>
    <request_args list="true">
        <arg>
            <key>api_key</key>
            <value>9e2568d68f182a2957878f3acedd9453</value>
        </arg>
        <arg>
            <key>auth_token</key>
            <value>aa0c41aa4532053e8d0097844ab9bc7d</value>
        </arg>
        <arg>
            <key>format</key>
            <value>xml</value>
        </arg>
        <arg>
            <key>generate_session_secret</key>
            <value>f1298956895d39110be92a672e0d2284</value>
         </arg>
         <arg>
            <key>method</key>
            <value>auth.getSession</value>
         </arg>
         <arg>
             <key>sig</key>
             <value>fcf80d658f35d66396ac521da7102782</value>
         </arg>
         <arg>
             <key>v</key>
             <value>1.0</value>
          </arg>
     </request_args>
</error_response>

可能是我的 MD5Utils 代码:

 public class Md5Utils
 
      private static String convertToHex(byte[] data)
      
           StringBuffer buf = new StringBuffer();
           for (int i = 0; i < data.length; i++) 
               int halfbyte = (data[i] >>> 4) & 0x0F;
               int two_halfs = 0;
               do 
                   if ((0 <= halfbyte) && (halfbyte <= 9))
                       buf.append((char) ('0' + halfbyte));
                   else
                      buf.append((char) ('a' + (halfbyte - 10)));
                      halfbyte = data[i] & 0x0F;
               
               while (two_halfs++ < 1);
            
        return buf.toString();
      

  public static String MD5(String text) 
  throws NoSuchAlgorithmException, UnsupportedEncodingException 
      MessageDigest md;
      md = MessageDigest.getInstance("MD5");
      byte[] md5hash = new byte[32];
      md.update(text.getBytes("iso-8859-1"), 0, text.length());
      md5hash = md.digest();
      return convertToHex(md5hash);
   

我可能做错了什么来生成不正确的签名?

如果有人可以帮助我或指出我正确的方向,我将不胜感激......

编程愉快,感谢阅读!

【问题讨论】:

【参考方案1】:

试试这个

    string GenerateSignature(IDictionary<string, string> parameters)
    
        StringBuilder signatureBuilder = new StringBuilder();

        // Sort the keys of the method call in alphabetical order
        List<string> keyList = ParameterDictionaryToList(parameters);
        keyList.Sort();

        // Append all the parameters to the signature input paramaters
        foreach (string key in keyList)
            signatureBuilder.Append(String.Format(CultureInfo.InvariantCulture, "0=1", key, parameters[key]));

        // Append the secret to the signature builder
        signatureBuilder.Append(ConfigurationManager.AppSettings["FBApiSecret"]);

        MD5 md5 = MD5.Create();
        // Compute the MD5 hash of the signature builder
        byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(signatureBuilder.ToString().Trim()));

        // Reinitialize the signature builder to store the actual signature
        signatureBuilder = new StringBuilder();

        // Append the hash to the signature
        foreach (byte hashByte in hash)
            signatureBuilder.Append(hashByte.ToString("x2", CultureInfo.InvariantCulture));

        return signatureBuilder.ToString();
    

    string CreateHTTPParameterList(IDictionary<string, string> parameterList)
    
        StringBuilder queryBuilder = new StringBuilder();
        parameterList.Add("api_key", ConfigurationManager.AppSettings["FBApiKey"]);
        parameterList.Add("v", "1.0");
        parameterList.Add("call_id", DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture));
        parameterList.Add("sig", GenerateSignature(parameterList));
        //parameterList.Add("sig", _sig);

        // Build the query
        foreach (KeyValuePair<string, string> kvp in parameterList)
        
            queryBuilder.Append(kvp.Key);
            queryBuilder.Append("=");
            queryBuilder.Append(HttpUtility.UrlEncode(kvp.Value));
            queryBuilder.Append("&");
        
        queryBuilder.Remove(queryBuilder.Length - 1, 1);

        return queryBuilder.ToString();
    

示例用法:

        Dictionary<string, string> parameterList = new Dictionary<string, string>();
        parameterList.Add("auth_token", authCode);
        parameterList.Add("format", "json");
        parameterList.Add("method", "facebook.auth.getSession");

        string req = CreateHTTPParameterList(parameterList);

我尝试从我的旧项目中复制/粘贴这些代码。 我希望它会对你有所帮助。

【讨论】:

【参考方案2】:

您在 generate_session_secret 您的密码中发送的参数有错误,它必须是真或假

你设置: 新 NameValuePair("generate_session_secret", SECRET),

您在帖子中设置的参数与签名存在冲突

【讨论】:

以上是关于Facebook:获取会话密钥时获取不正确的签名 (104)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 上获取 FB Chat 的 API 密钥和会话密钥和会话密钥

无法从密钥库中获取相同的签名

班级云相册code获取失败怎么解决

在localhost上运行Facebook应用程序

org.opensaml.common.SAMLRuntimeException:无法获取 SP 签名密钥

获取 GPG 公钥的密钥签名/指纹