【问题标题】:Validate and get data from Facebook cookie using OAUTH 2.0使用 OAUTH 2.0 验证并从 Facebook cookie 获取数据
【发布时间】:2011-11-22 13:29:40
【问题描述】:

我有一个用 GWT 制作的网页。在那里,我使用所有登录 facebook 的东西和一个操纵的 gwtfb 库,一切正常。迁移到 oauth 2.0 后,现在发送到服务器的 cookie 已更改为加密的。

我想得到一个java示例代码,实现在服务器中与旧的一样:

  • 我需要像使用 cookie md5 技巧之前一样验证调用,以了解调用是否由我的客户端页面进行。
  • 从该 cookie 中获取数据:我需要 facebook 用户。

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

提前致谢。

【问题讨论】:

    标签: java facebook cookies oauth


    【解决方案1】:

    好吧,虽然我有一些很好的答案,但我还是用我在博客中写的内容来回答自己: http://pablocastilla.wordpress.com/2011/09/25/how-to-implement-oauth-f/

    现在 cookie 发生了很大变化:它是加密的,没有访问令牌,它的内容格式也发生了很大变化。在这里你有几个链接在谈论它:

    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;
        }
    }
    

    【讨论】:

    • if (data.getString("algorithm") != "HMAC-SHA256") { 正确的是:if (!"HMAC-SHA256".equals(data.getString("algorithm")) ) {
    【解决方案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());
    

    你可以在这里看到代码,它使用Jackson解析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。您无需担心签署访问令牌,因为它是不可猜测的。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 但我需要在服务器中进行。 java没有sdk :(.
      猜你喜欢
      • 2012-01-22
      • 2011-04-10
      • 1970-01-01
      • 2013-01-28
      • 2015-05-05
      • 2011-02-28
      • 2011-11-15
      • 2015-04-14
      • 1970-01-01
      相关资源
      最近更新 更多