使用OAuth通过Facebook账号登录Google App Engine的Java示例

39

我搜索了很多,阅读了许多博客、文章和教程,但到目前为止还没有得到使用Facebook账号登录我的应用程序的有效示例。

我知道我必须使用OAuth,获取令牌、授权等...

有人可以分享一个例子吗?

5个回答

52

以下是我在App Engine上的操作步骤:

第一步:在Facebook上注册一个“应用程序”(参见https://developers.facebook.com/)。您需要为应用程序命名并提供一个URL。您注册的URL是处理登录的页面(JSP或servlet)的URL。注册后,您会获得两个字符串:“应用程序ID”和“应用程序秘钥”(后者是您的密码,请勿公开或在HTML中写入)。

例如,假设我注册的URL是“http://myappengineappid.appspot.com/signin_fb.do”。

第二步:从一个网页(比如一个按钮)上,您将用户重定向到Facebook上的以下URL,并在下面的示例中用您的应用程序ID替换“myfacebookappid”。您还需要选择要请求用户的哪些权限(或“范围”)(参见https://developers.facebook.com/docs/reference/api/permissions/)。在此示例中,我仅请求访问用户的电子邮件。

(有一个有用的信息是您也可以传递一个可选字符串,该字符串会在“state”参数中以不变形式返回。例如,我传递了用户数据存储键,以便在Facebook将键传递回给我时,我可以检索用户。但在本示例中,我没有这样做。)

以下是JSP片段:

<%@page import="java.net.URLEncoder" %>
<%
    String fbURL = "http://www.facebook.com/dialog/oauth?client_id=myfacebookappid&redirect_uri=" + URLEncoder.encode("http://myappengineappid.appspot.com/signin_fb.do") + "&scope=email";
%>

<a href="<%= fbURL %>"><img src="/img/facebook.png" border="0" /></a>

3) 用户将被转到 Facebook,并被要求批准您请求的权限。然后,用户将被重定向回您注册的 URL。在此示例中,这是“http://myappengineappid.appspot.com/signin_fb.do”,它在我的 web.xml 中映射到以下 servlet:

import org.json.JSONObject;
import org.json.JSONException;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SignInFB extends HttpServlet {

    public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {            
        String code = req.getParameter("code");
        if (code == null || code.equals("")) {
            // an error occurred, handle this
        }

        String token = null;
        try {
            String g = "https://graph.facebook.com/oauth/access_token?client_id=myfacebookappid&redirect_uri=" + URLEncoder.encode("http://myappengineappid.appspot.com/signin_fb.do", "UTF-8") + "&client_secret=myfacebookappsecret&code=" + code;
            URL u = new URL(g);
            URLConnection c = u.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream()));
            String inputLine;
            StringBuffer b = new StringBuffer();
            while ((inputLine = in.readLine()) != null)
                b.append(inputLine + "\n");            
            in.close();
            token = b.toString();
            if (token.startsWith("{"))
                throw new Exception("error on requesting token: " + token + " with code: " + code);
        } catch (Exception e) {
                // an error occurred, handle this
        }

        String graph = null;
        try {
            String g = "https://graph.facebook.com/me?" + token;
            URL u = new URL(g);
            URLConnection c = u.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream()));
            String inputLine;
            StringBuffer b = new StringBuffer();
            while ((inputLine = in.readLine()) != null)
                b.append(inputLine + "\n");            
            in.close();
            graph = b.toString();
        } catch (Exception e) {
                // an error occurred, handle this
        }

        String facebookId;
        String firstName;
        String middleNames;
        String lastName;
        String email;
        Gender gender;
        try {
            JSONObject json = new JSONObject(graph);
            facebookId = json.getString("id");
            firstName = json.getString("first_name");
            if (json.has("middle_name"))
               middleNames = json.getString("middle_name");
            else
                middleNames = null;
            if (middleNames != null && middleNames.equals(""))
                middleNames = null;
            lastName = json.getString("last_name");
            email = json.getString("email");
            if (json.has("gender")) {
                String g = json.getString("gender");
                if (g.equalsIgnoreCase("female"))
                    gender = Gender.FEMALE;
                else if (g.equalsIgnoreCase("male"))
                    gender = Gender.MALE;
                else
                    gender = Gender.UNKNOWN;
            } else {
                gender = Gender.UNKNOWN;
            }
        } catch (JSONException e) {
            // an error occurred, handle this
        }

        ...

我已删除错误处理代码,因为您可能希望以不同于我的方式进行处理。(另外,“Gender”当然是我定义的一个类。)此时,您可以将数据用于任何您想要的目的,例如注册新用户或查找现有用户以登录。请注意,“myfacebookappsecret”字符串应该是来自Facebook的您的应用程序秘密。

您需要“org.json”包才能使用此代码,您可以在http://json.org/java/上找到它(只需获取.java文件并将其添加到具有org / json文件夹结构的代码中即可)。

我希望这可以帮助到您。如果有任何不清楚的地方,请发表评论,我会更新回答。

Ex animo,- Alexander。

****更新****

我想再添加一些信息,如果有些部分看起来有点过多,请见谅。

要能够通过用户的Facebook帐户登录用户,您需要知道我们正在谈论哪个数据存储中的用户。如果是新用户,则很容易创建一个新用户对象(带有名为“facebookId”的字段,或者您想要称之为什么,其值来自Facebook),将其持久化存储在数据存储中并登录用户。

如果用户存在,则需要具有包含facebookId的字段。当用户从Facebook重定向时,您可以获取facebookId,并在数据存储中查找要登录的用户。

如果您已经有了用户,则需要让他们按照您通常的方式登录,以便您知道他们是谁,然后将其发送到Facebook,获取返回的facebookId并更新其用户对象。这样,他们下次就可以使用Facebook登录了。

另一个小提示:用户将在Facebook上呈现一个屏幕,要求允许您的应用程序访问您请求的任何作用域,没有任何绕过此操作的方法(您请求的作用域越少,它看起来越不具侵入性)。但是,这仅会在用户第一次重定向时发生(除非您稍后请求更多作用域,然后它会再次询问)。


2
您可以使用此代码执行两个操作:(1)允许新用户点击“使用Facebook注册”,(2)允许现有用户通过单击“使用您的Facebook帐户登录”进行登录。他们都可以单击同一个链接,当上面的servlet运行时,您可以检查数据库并查看是否有使用此facebookId注册的用户。如果是,则可以将该用户登录。如果没有,则可以创建一个新用户并存储facebookId。是的,如果用户已登录Facebook并已批准任何权限,则此代码将自动登录该用户,无需单击任何位置。 - yngling
1
一个小的额外说明:当然,您也可以允许您应用程序的现有用户使用Facebook登录(即使用其facebookId更新其用户对象)。例如,这可以通过在我简要提到的状态参数中传递用户的数据存储键,然后让上面的servlet获取它并使用facebookId更新用户来完成(或者您可以使用会话来检测用户)。 - yngling
@nanospeck 使用 URLEncode.encode(urlS, enc) https://docs.oracle.com/javase/7/docs/api/java/net/URLEncoder.html#encode(java.lang.String,%20java.lang.String) - matteolel
性别 gender;这里出现了错误,请问我们从哪里可以获取 Gender 类? - Kunal Saini
@KunalSaini 谢谢你的提问。正如我在帖子中提到的那样,性别是我创建的一个类。它只是一个类型安全的枚举,请尝试以下代码: public class Gender { public static final Gender UNKNOWN = new Gender(); public static final Gender MALE = new Gender(); public static final Gender FEMALE = new Gender();private Gender() {}} - yngling
显示剩余18条评论

6
您可以尝试使用face4j https://github.com/nischal/face4j/wiki。我们在我们的产品http://grabinbox.com 中使用它,并将其开源供任何人使用。它在GAE上运行良好。
wiki上有一个示例,可以帮助您在几分钟内集成Facebook登录。
face4j使用oAuth 2.0和Facebook Graph API。

@Jus12,这个叫做face4j而不是twitter4j。所以我猜不行。 - NimChimpsky

3

在尝试手动实现OAuth签名时遇到了很多困难。我花费了很多时间尝试调试我的令牌未得到授权的问题-这是一个常见问题。不幸的是,对我来说,这些解决方案都没有起作用,所以我最终使用了Scribe,这是一个非常方便的Java OAuth库,除Facebook外还支持其他提供程序(例如Google、Twitter等)。



0

我不相信facebook-java-api 3.0.4符合FB身份验证的最新文档要求。相反,我按照被接受的答案中的步骤,然后使用了restfb框架。 - s_t_e_v_e
@s_t_e_v_e 我并不惊讶;FB 更换他们的 API 的频率比模特换衣服的频率还要高 ;) 很高兴听到你找到了解决方案 :) - Adrian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接