Code ví dụ JSP Servlet login bằng Facebook (Java Web)

Code ví dụ JSP Servlet login bằng Facebook (Java Web).

Đăng nhập ứng dụng Java Web bằng Facebook

Ở bài này mình sẽ hướng dẫn viết ứng dụng java web bằng JSP – Servlet để truy cập facebook.

Thông thường các ứng dụng đăng nhập bằng facebook sẽ sử dụng SDK cho từng nền tảng (Facebook SDK cho Android, cho Javascript…) nhưng ở đây mình sẽ không dùng SDK mà sẽ tạo thủ công quy trình đăng nhập ứng dụng bằng facebook để mọi người hiểu rõ nguyên lý và luồng chạy.

Đầu tiên ta tạo một ứng dụng trên facebook để thực hiện đăng nhập Java web bằng facebook qua ứng dụng này.

(Xem lại: Tạo ứng dụng facebook để đăng nhập thay tài khoản.)

Ứng dụng mình tạo trên facebook là demo-login với id là: 359123991240252 và khóa ứng dụng là: d07e182d8495df6930665d6c39fbe8ac

Ví dụ ứng dụng facebook để đăng nhập cho website

Code ví dụ JSP Servlet login bằng Facebook (Java Web) stackjava.com

Tạo ứng dụng Java Web với JSP – Servlet

Ở đây mình dùng server là tomcat 8cấu hình https cho tomcat (ứng dụng login từ facebook yêu cầu kết nối https)

Tạo Dynamic Web Project

dynamic web

Ứng dụng Java Web này mình tạo sẽ chạy trên tomcat 8

Tạo ứng dụng Java Web vớiJSP - Servlet

Cấu trúc Project hoàn chỉnh:

Code ví dụ JSP Servlet login bằng Facebook (Java Web)

Mình dùng thư viện restfb để truy vấn thông tin với facebook api, dùng thư viện org.apache.httpcomponents (httpclient, httpcore, fluent) để gửi request tới facebook, thư viện gson để convert dữ liệu từ dạng json và ngược lại.

(Download các thư viện trên tại đây)

Class Constants.java:

Dùng để khai báo id, secret và redirect uri của ứng dụng demo login.

  • Constants.java
  • package stackjava.com.accessfacebook.common;
  • public class Constants {
  • public static String FACEBOOK_APP_ID = "359123991240252";
  • public static String FACEBOOK_APP_SECRET = "d07e182d8495df6930665d6c39fbe8ac";
  • public static String FACEBOOK_REDIRECT_URL = "https://localhost:8443/AccessFacebook/login-facebook";
  • public static String FACEBOOK_LINK_GET_TOKEN = "https://graph.facebook.com/oauth/access_token?client_id=%s&client_secret=%s&redirect_uri=%s&code=%s";
  • }
package stackjava.com.accessfacebook.common;

public class Constants {
  public static String FACEBOOK_APP_ID = "359123991240252";
  public static String FACEBOOK_APP_SECRET = "d07e182d8495df6930665d6c39fbe8ac";
  public static String FACEBOOK_REDIRECT_URL = "https://localhost:8443/AccessFacebook/login-facebook";
  public static String FACEBOOK_LINK_GET_TOKEN = "https://graph.facebook.com/oauth/access_token?client_id=%s&client_secret=%s&redirect_uri=%s&code=%s";

}

Trang login:

  • login.jsp
  • <html>
  • <head>
  • <title>Login</title>
  • </head>
  • <body>
  • <h1>login</h1>
  • <a href="https://www.facebook.com/dialog/oauth?client_id=359123991240252&redirect_uri=https://localhost:8443/AccessFacebook/login-facebook">Login Facebook</a>
  • </body>
  • </html>
<html>
<head>
  <title>Login</title>
</head>
<body>
  <h1>login</h1>
  <a href="https://www.facebook.com/dialog/oauth?client_id=359123991240252&redirect_uri=https://localhost:8443/AccessFacebook/login-facebook">Login Facebook</a>
</body>
</html>

Đường link

https://www.facebook.com/dialog/oauth?client_id=359123991240252&redirect_uri=https://localhost:8443/AccessFacebook/login-facebook dùng để gọi hộp thoại Đăng nhập và cài đặt URL chuyển hướng.

Nó sẽ chuyển hướng người dùng tới trang của facebook để xác nhận quyền truy cập của ứng dụng demo-login. rồi sau đấy gửi kết quả + chuyển hướng về url là https://localhost:8443/AccessFacebook/login-facebook

Định dạng của đường linh gọi hộp thoại đăng nhập và chuyển hướng URL là:

  • https://www.facebook.com/v2.12/dialog/oauth?
  • client_id={app-id}
  • &redirect_uri={redirect-uri}
  • &state={state-param}
https://www.facebook.com/v2.12/dialog/oauth?
  client_id={app-id}
  &redirect_uri={redirect-uri}
  &state={state-param}

Nếu bạn chọn Hủy thì nó sẽ trả về kết quả tới:

  • YOUR_REDIRECT_URI?
  • error_reason=user_denied
  • &error=access_denied
  • &error_description=Permissions+error.
YOUR_REDIRECT_URI?
 error_reason=user_denied
 &error=access_denied
 &error_description=Permissions+error.

Nếu bạn đồng ý đăng nhập bằng facebook (ở trên là button ‘Tiếp tục dưới tên Kai’) thì nó sẽ trả một đoạn code tới https://localhost:8443/AccessFacebook/login-facebook

Class LoginFacebookServlet.java

Xử lý kết quả trả về từ facebook

  • package stackjava.com.accessfacebook.servlet;
  • import java.io.IOException;
  • import javax.servlet.RequestDispatcher;
  • import javax.servlet.ServletException;
  • import javax.servlet.annotation.WebServlet;
  • import javax.servlet.http.HttpServlet;
  • import javax.servlet.http.HttpServletRequest;
  • import javax.servlet.http.HttpServletResponse;
  • import com.restfb.types.User;
  • import stackjava.com.accessfacebook.common.RestFB;
  • @WebServlet("/login-facebook")
  • public class LoginFacebookServlet extends HttpServlet {
  • private static final long serialVersionUID = 1L;
  • public LoginFacebookServlet() {
  • super();
  • }
  • protected void doGet(HttpServletRequest request, HttpServletResponse response)
  • throws ServletException, IOException {
  • String code = request.getParameter("code");
  • if (code == null || code.isEmpty()) {
  • RequestDispatcher dis = request.getRequestDispatcher("login.jsp");
  • dis.forward(request, response);
  • } else {
  • String accessToken = RestFB.getToken(code);
  • User user = RestFB.getUserInfo(accessToken);
  • request.setAttribute("id", user.getId());
  • request.setAttribute("name", user.getName());
  • RequestDispatcher dis = request.getRequestDispatcher("index.jsp");
  • dis.forward(request, response);
  • }
  • }
  • protected void doPost(HttpServletRequest request, HttpServletResponse response)
  • throws ServletException, IOException {
  • doGet(request, response);
  • }
  • }
package stackjava.com.accessfacebook.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.restfb.types.User;

import stackjava.com.accessfacebook.common.RestFB;

@WebServlet("/login-facebook")
public class LoginFacebookServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

  public LoginFacebookServlet() {
    super();
  }

  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    String code = request.getParameter("code");
    
    if (code == null || code.isEmpty()) {
      RequestDispatcher dis = request.getRequestDispatcher("login.jsp");
      dis.forward(request, response);
    } else {
      String accessToken = RestFB.getToken(code);
      User user = RestFB.getUserInfo(accessToken);
      request.setAttribute("id", user.getId());
      request.setAttribute("name", user.getName());
      RequestDispatcher dis = request.getRequestDispatcher("index.jsp");
      dis.forward(request, response);
    }
    
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doGet(request, response);
  }

}

Trường hợp người dùng không đồng ý đăng nhập bằng facebook thì ta sẽ quay ngược lại trang login.

Trường hợp người dùng đồng ý đăng nhập bằng facebook thì ta sẽ đổi đoạn code nhận được sang access token và dùng access token đó để lấy thông tin id, name của tài khoản facebook (bạn có thể tạo mới tài khoản từ thông tin này, thêm user vào session… để trường hợp đăng nhập bằng facebook có tác dụng như đăng nhập bằng username/password thông thường)

Lưu ý, đoạn code gửi về sau khi xác nhận hộp thoại và access token là khác nhau.

Để có mã truy cập, ta tạo yêu cầu HTTP GET đến điểm cuối OAuth sau:

  • GET https://graph.facebook.com/v2.12/oauth/access_token?
  • client_id={app-id}
  • &redirect_uri={redirect-uri}
  • &client_secret={app-secret}
  • &code={code-parameter}
GET https://graph.facebook.com/v2.12/oauth/access_token?
   client_id={app-id}
   &redirect_uri={redirect-uri}
   &client_secret={app-secret}
   &code={code-parameter}

Kết quả nhận được nếu thành công là:

  • {
  • "access_token": {access-token},
  • "token_type": {type},
  • "expires_in": {seconds-til-expiration}
  • }
{
  "access_token": {access-token}, 
  "token_type": {type},
  "expires_in":  {seconds-til-expiration}
}

Class RestFB.java dùng để truy vấn tới tài khoản facebook (lấy access token, thông tin tài khoản facebook)

  • RestFB.java
  • package stackjava.com.accessfacebook.common;
  • import java.io.IOException;
  • import org.apache.http.client.ClientProtocolException;
  • import org.apache.http.client.fluent.Request;
  • import com.google.gson.Gson;
  • import com.google.gson.JsonObject;
  • import com.restfb.DefaultFacebookClient;
  • import com.restfb.FacebookClient;
  • import com.restfb.Version;
  • import com.restfb.types.User;
  • public class RestFB {
  • public static String getToken(final String code) throws ClientProtocolException, IOException {
  • String link = String.format(Constants.FACEBOOK_LINK_GET_TOKEN, Constants.FACEBOOK_APP_ID, Constants.FACEBOOK_APP_SECRET, Constants.FACEBOOK_REDIRECT_URL, code);
  • String response = Request.Get(link).execute().returnContent().asString();
  • JsonObject jobj = new Gson().fromJson(response, JsonObject.class);
  • String accessToken = jobj.get("access_token").toString().replaceAll("\"", "");
  • return accessToken;
  • }
  • public static User getUserInfo(String accessToken) {
  • FacebookClient facebookClient = new DefaultFacebookClient(accessToken, Constants.FACEBOOK_APP_SECRET, Version.LATEST);
  • return facebookClient.fetchObject("me", User.class);
  • }
  • }
package stackjava.com.accessfacebook.common;

import java.io.IOException;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.fluent.Request;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.restfb.DefaultFacebookClient;
import com.restfb.FacebookClient;
import com.restfb.Version;
import com.restfb.types.User;

public class RestFB {
  
  public static String getToken(final String code) throws ClientProtocolException, IOException {
    String link = String.format(Constants.FACEBOOK_LINK_GET_TOKEN, Constants.FACEBOOK_APP_ID, Constants.FACEBOOK_APP_SECRET, Constants.FACEBOOK_REDIRECT_URL, code);
    String response = Request.Get(link).execute().returnContent().asString();
    JsonObject jobj = new Gson().fromJson(response, JsonObject.class);
    String accessToken = jobj.get("access_token").toString().replaceAll("\"", "");
    return accessToken;
  }
  
  public static User getUserInfo(String accessToken) {
    FacebookClient facebookClient = new DefaultFacebookClient(accessToken, Constants.FACEBOOK_APP_SECRET, Version.LATEST);
    return facebookClient.fetchObject("me", User.class);
  }

}

Nếu không dùng thư viện RestFB thì bạn có thể dùng URL sau để lấy thông tin của user:
https://graph.facebook.com/me?access_token=... thông tin trả về sẽ gồm id và name.

(Bạn cũng có thể lấy thêm nhiều trường khác như email, comment, image… nhưng cần phải có thêm permission, ở đây mình chỉ thực hiện đăng nhập nên chỉ cần permission để lấy public profile)

Trang index.jsp

  • index.jsp
  • <%@ page language="java" contentType="text/html; charset=UTF-8"
  • pageEncoding="UTF-8"%>
  • <html>
  • <head>
  • <title>index</title>
  • </head>
  • <body>
  • <h1>Index</h1>
  • <%
  • String id = request.getAttribute("id").toString();
  • String name = request.getAttribute("name").toString();
  • out.print("Id: " + id);
  • out.print("<br/>Name: " + name);
  • %>
  • </body>
  • </html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<html>
<head>
<title>index</title>
</head>
<body>
  <h1>Index</h1>
  <%
    String id = request.getAttribute("id").toString();
    String name = request.getAttribute("name").toString();
    out.print("Id: " + id);
    out.print("<br/>Name: " + name);
  %>
</body>
</html>

Demo:

login facebook bằng java web

Trường hợp không đồng ý đăng nhập

 login facebook bằng jsp servlet

Trường hợp đồng ý đăng nhập (nếu đồng ý thì lần sau sẽ không hỏi lại nữa)

đăng nhập facebook bằng jsp servlet đăng nhập facebook với java web

Code ví dụ JSP Servlet login bằng Facebook (Java Web) stackjava.com

Okay, Done!

Download code ví dụ trên tại đây.

 

References:

https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow

https://developers.facebook.com/docs/graph-api/reference/user/accounts/

stackjava.com