I'm building a JSP application and I would like to use Facebook Connect as one path for user registration and authentication, but I'm not finding much information about how to fetch and parse the FB cookie or even the right flow. I'm trying to merge the information found in the official documentation with a step by step guide like this one but for Java. I am not opposed to relying 开发者_如何学Con libraries like Social Java but understanding the steps would be helpful. Here are the 3 use cases I'm trying to satisfy.
- Unauthenticated/unregistered user on my site clicks on "Facebook Connect" button to sign up (capturing email, name and profile ID) and and sign in.
- Unauthenticated user clicks on ""Facebook Connect" button to create a valid session on my domain.
- Authenticated and registered user without a connected Facebook profile clicks on "Facebook Connect" and associates a Facebook profile ID (and the option to update their email and name) with their existing profile.
For this project I have a Profile class that looks like this (I'm using the excellent Project Lombok with Hibernate)
@Entity
@Data
public class Profile implements java.io.Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String username;
private String password;
private String displayName;
private String email;
private String zipCode;
private String mobileNumber;
private String facebookId;
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime dateCreated;
private int status;
private int level;
}
Status and Level really should be enums, but I'm trying to keep the code tiny for this question.
Disclaimer:I've been reading a lot of blogs about how to setup Facebook Connect for user registration and authentication, but they are for the most part based on PHP and older versions of the Facebook API (even some SO questions point to the old wiki in their accepted answers). This seems like a perfect application of the SO community.
Here is servlet solution I use. With little tweaking you can meke it work in any JSP with simple username-password form. No javascript needed!!! As far as address and phone number go read this: http://developers.facebook.com/blog/post/447
FBAuthServlet
public class FBAuthServlet extends HttpServlet {
private static final Logger log = Logger.getLogger(FBAuthServlet.class);
private static final long serialVersionUID = 1L;
private UserService userService = //here goes your user service implementation
public FBAuthServlet() {
super();
}
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if ("y".equals(request.getParameter("FacebookLogin"))) {
response.sendRedirect(FaceBookConfig.getLoginRedirectURL());
return;
}
String code = req.getParameter("code");
if (StringUtil.isNotBlankStr(code)) {
String authURL = FaceBookConfig.getAuthURL(code);
URL url = new URL(authURL);
try {
String result = readURL(url);
String accessToken = null;
Integer expires = null;
String[] pairs = result.split("&");
for (String pair : pairs) {
String[] kv = pair.split("=");
if (kv.length != 2) {
res.sendRedirect(FaceBookConfig.MAINURL);
} else {
if (kv[0].equals("access_token")) {
accessToken = kv[1];
}
if (kv[0].equals("expires")) {
expires = Integer.valueOf(kv[1]);
}
}
}
if (accessToken != null && expires != null) {
User user = authFacebookLogin(accessToken, request.getRemoteAddr());
if (user != null && user.getFacebookId() != null) {
//forward to spring security filter chain
res.sendRedirect(FaceBookConfig.MAINURL + "/j_spring_security_check?j_username=" + user.getEmail() + "&FaceBookId=" + user.getFacebookId());
} else if (user != null && StringUtil.isNullOrBlank(user.getFacebookId())) {
res.sendRedirect(FaceBookConfig.MAINURL + "/login.html?login_error=You are not Registered By Facebook Connect");
} else {
res.sendRedirect(FaceBookConfig.MAINURL);
}
}
} catch (Exception e) {
e.printStackTrace();
res.sendRedirect(FaceBookConfig.MAINURL);
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
public void init() throws ServletException {
}
private String readURL(URL url) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = url.openStream();
int r;
while ((r = is.read()) != -1) {
baos.write(r);
}
return new String(baos.toByteArray());
}
private User authFacebookLogin(String accessToken, String ip) {
try {
String content = IOUtil.urlToString(new URL("https://graph.facebook.com/me?access_token=" + accessToken));
JSONObject resp = new JSONObject(content);
String facebookid = resp.getString("id");
String firstName = resp.getString("first_name");
String lastName = resp.getString("last_name");
String email = resp.getString("email");
log.info("Facebook response: " + content);
CreateUserRequestCommand comm = new CreateUserRequestCommand();
comm.setEmail(email);
comm.setFacebookId(facebookid);
comm.setFirst(StringAndDateUtils.safeChar(firstName));
comm.setLast(StringAndDateUtils.safeChar(lastName));
//if success login
if (userService.getUserByEmail(email) == null) {
//if first time login
User u = userService.createUser(comm, ip);
return u;
} else {//if existed
User existedUser = userService.getUserByEmail(email);
return existedUser;
}
} catch (Throwable ex) {
ex.printStackTrace();
}
return null;
}
}
FBEnableServlet
public class FBEnableServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private UserService userService = (UserService) ServiceLocator.getContext().getBean("userService");
public FBEnableServlet() {
super();
}
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if ("y".equals(request.getParameter("EnableFacebookConnect"))) {
response.sendRedirect(FaceBookConfig.getEnableRedirectURL());
return;
}
String code = req.getParameter("code");
if (StringUtil.isNotBlankStr(code)) {
String authURL = FaceBookConfig.getEnableAuthURL(code);
URL url = new URL(authURL);
try {
String result = readURL(url);
String accessToken = null;
Integer expires = null;
String[] pairs = result.split("&");
for (String pair : pairs) {
String[] kv = pair.split("=");
if (kv.length != 2) {
res.sendRedirect(FaceBookConfig.MAINURL);
} else {
if (kv[0].equals("access_token")) {
accessToken = kv[1];
}
if (kv[0].equals("expires")) {
expires = Integer.valueOf(kv[1]);
}
}
}
if (accessToken != null && expires != null) {
User user = authFacebookLogin(accessToken, request.getRemoteAddr());
String loginedEmail = "";
try {
loginedEmail = SecurityContextHolder.getContext().getAuthentication().getName();
} catch (Exception ex) {
}
System.out.println("Logined email = " + loginedEmail);
System.out.println("Facebook Login email = " + user.getEmail());
if (user != null && user.getFacebookId() != null && user.getEmail().equals(loginedEmail)) {
userService.setFaceBookid(user.getFacebookId());
//forward to spring security filter chain
res.sendRedirect(FaceBookConfig.MAINURL + "/j_spring_security_check?j_username=" + user.getEmail() + "&FaceBookId=" + user.getFacebookId());
} else {
res.sendRedirect(FaceBookConfig.MAINURL + "/secure/myAccount.html?message=Please login Facebook with same Email,you Login with " + user.getEmail());
}
}
} catch (Exception e) {
e.printStackTrace();
res.sendRedirect(FaceBookConfig.MAINURL);
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
public void init() throws ServletException {
}
private String readURL(URL url) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = url.openStream();
int r;
while ((r = is.read()) != -1) {
baos.write(r);
}
return new String(baos.toByteArray());
}
private User authFacebookLogin(String accessToken, String ip) {
try {
String content = IOUtil.urlToString(new URL("https://graph.facebook.com/me?access_token=" + accessToken));
JSONObject resp = new JSONObject(content);
String facebookid = resp.getString("id");
String email = resp.getString("email");
User existedUser = userService.getUserByEmail(email);
if (existedUser == null) {
return null;
} else {
existedUser.setFacebookId(facebookid);
return existedUser;
}
} catch (Throwable ex) {
ex.printStackTrace();
}
return null;
}
}
Haven't used it myself, but there seems to be a (inofficial) Java API on Google Code: http://code.google.com/p/facebook-java-api/
It doesn't take long to do the integration yourself, it's just OAuth 2.0 followed by an http request for some user details (json formatted).
We have some code in github (that's quite tied to our social model) that checks the OAuth token and returns the user id (link at bottom of post). You can get the current user's access token from the cookie that the Facebook Connect JavaScript writes (the cookie name begins 'fbs_').
https://github.com/mbst/common-social/blob/master/src/main/java/com/metabroadcast/common/social/auth/facebook/FacebookAccessTokenChecker.java
精彩评论