2011-09-22 81 views
3

我有一个以GWT制作的网页。在那里我使用所有的登录Facebook的东西与操纵gwtfb库,一切正常。现在迁移到oauth 2.0后,发送到服务器的cookie已更改为加密的cookie。验证并使用OAUTH 2.0从Facebook cookie获取数据

我想,在服务器实现比老同一个Java示例代码:

  • 我需要验证调用,比如我使用cookie MD5伎俩知道以前那样该呼叫已由我的客户页面完成。
  • 从该cookie获取数据:我需要facebook用户。

如果可能不调用FB,只使用cookie数据。

在此先感谢。

回答

8

好吧,虽然我有几个很好的答案,我回答自己什么我已经写在我的博客: http://pablocastilla.wordpress.com/2011/09/25/how-to-implement-oauth-f/

现在的饼干已经改变了很多:它是加密的,不具有的accessToken和其内容格式已经改变了很多。在这里,你有几个环节说起吧:

http://developers.facebook.com/docs/authentication/signed_request/

http://developers.facebook.com/docs/authentication/

http://blog.sociablelabs.com/2011/09/19/server-side-changes-facebook-oauth-2-0-upgrade/

所以验证cookie的,从它那里得到用户并获得访问令牌,你可以使用此代码:

public class FaceBookSecurity { 

// return the fb user in the cookie. 
public static String getFBUserFromCookie(HttpServletRequest request) 
     throws Exception { 
    Cookie fbCookie = getFBCookie(request); 

    if (fbCookie == null) 
     return null; 

    // gets cookie value 
    String fbCookieValue = fbCookie.getValue(); 

    // splits it. 
    String[] stringArgs = fbCookieValue.split("\\."); 
    String encodedPayload = stringArgs[1]; 

    String payload = base64UrlDecode(encodedPayload); 

    // gets the js object from the cookie 
    JsonObject data = new JsonObject(payload); 

    return data.getString("user_id"); 

} 

public static boolean ValidateFBCookie(HttpServletRequest request) 
     throws Exception { 

    Cookie fbCookie = getFBCookie(request); 

    if (fbCookie == null) 
     throw new NotLoggedInFacebookException(); 

    // gets cookie information 
    String fbCookieValue = fbCookie.getValue(); 

    String[] stringArgs = fbCookieValue.split("\\."); 
    String encodedSignature = stringArgs[0]; 
    String encodedPayload = stringArgs[1]; 

    //decode 
    String sig = base64UrlDecode(encodedSignature); 
    String payload = base64UrlDecode(encodedPayload); 

    // gets the js object from the cookie 
    JsonObject data = new JsonObject(payload); 

    if (!data.getString("algorithm").Equals("HMAC-SHA256")) { 
     return false; 
    } 

    SecretKey key = new SecretKeySpec(
      ApplicationServerConstants.FacebookSecretKey.getBytes(), 
      "hmacSHA256"); 

    Mac hmacSha256 = Mac.getInstance("hmacSHA256"); 
    hmacSha256.init(key); 
    // decode the info. 
    byte[] mac = hmacSha256.doFinal(encodedPayload.getBytes()); 

    String expectedSig = new String(mac); 

    // compare if the spected sig is the same than in the cookie. 
    return expectedSig.equals(sig); 

} 

public static String getFBAccessToken(HttpServletRequest request) 
     throws Exception { 
    Cookie fbCookie = getFBCookie(request); 

    String fbCookieValue = fbCookie.getValue(); 

    String[] stringArgs = fbCookieValue.split("\\."); 
    String encodedPayload = stringArgs[1]; 

    String payload = base64UrlDecode(encodedPayload); 

    // gets the js object from the cookie 
    JsonObject data = new JsonObject(payload); 

    String authUrl = getAuthURL(data.getString("code")); 
    URL url = new URL(authUrl); 
    URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), 
      url.getQuery(), null); 
    String result = readURL(uri.toURL()); 

    String[] resultSplited = result.split("&"); 

    return resultSplited[0].split("=")[1]; 

} 

// creates the url for calling to oauth. 
public static String getAuthURL(String authCode) { 
    String url = "https://graph.facebook.com/oauth/access_token?client_id=" 
      + ApplicationConstants.FacebookApiKey 
      + "&redirect_uri=&client_secret=" 
      + ApplicationServerConstants.FacebookSecretKey + "&code=" 
      + authCode; 

    return url; 
} 

// reads the url. 
private static String readURL(URL url) throws IOException { 

    InputStream is = url.openStream(); 

    InputStreamReader inStreamReader = new InputStreamReader(is); 
    BufferedReader reader = new BufferedReader(inStreamReader); 

    String s = ""; 

    int r; 
    while ((r = is.read()) != -1) { 
     s = reader.readLine(); 
    } 

    reader.close(); 
    return s; 
} 

private static String base64UrlDecode(String input) { 
    String result = null; 
    Base64 decoder = new Base64(true); 
    byte[] decodedBytes = decoder.decode(input); 
    result = new String(decodedBytes); 
    return result; 
} 

    private static Cookie getFBCookie(HttpServletRequest request) 
    { 
     Cookie[] cookies = request.getCookies(); 

     if (cookies == null) 
      return null; 

     Cookie fbCookie = null; 

     for (Cookie c : cookies) { 
      if (c.getName().equals(
       "fbsr_" + ApplicationServerConstants.FacebookApiKey)) { 
       fbCookie = c; 
      } 
     } 
     return fbCookie; 
    } 
} 
+2

if(data.getString(“algorithm”)!= “HMAC-SHA256”){ 正确的是: 如果(! “HMAC-SHA256” .equals(data.getString( “算法”))){ – uwe

1

我认为cookie数据是任意格式的 - 因为你不应该自己解释它? SDK肯定会为你验证cookie吗?

+0

但我需要在服务器中做到这一点。没有sdk的java :(。 –

2

我只是说这BatchFB的新版本(2.1.1):http://code.google.com/p/batchfb/

获得用户ID:

FacebookCookie data = FacebookCookie.decode(cookie, YOURAPPSECRET); 
System.out.println("Facebook user id is " + data.getFbId()); 

你可以看到这里的代码,它使用杰克逊解析在JSON和javax.crypto.Mac中来验证签名:

http://code.google.com/p/batchfb/source/browse/trunk/src/com/googlecode/batchfb/FacebookCookie.java

不幸的是获得访问令牌是相当多的复杂。 fbsr_ cookie中包含的数据包含一个“代码”,然后您可以使用该代码来获取图形api以获取真正的访问令牌......您必须将它存储在某个cookie或会话中。这是令人难以置信的跛脚。

更好的解决方案是从javascript设置您自己的访问令牌cookie。每次调用FB.getLoginStatus()时,都要设置(或删除)您自己的cookie。你不必担心签名访问令牌,因为它是不可猜测的。