I did use OpenID 2.0 which is going to be deprecated (obsolete) in 2015 for Google. What is a simple way to migrate if I'm using servlets?
I spent several hours reading from Google website and if you think that Google API Client is unfriendly or over complex you should continue reading this. I took look at Apache Oltu, however, the documentation doesn't have example for Google and also I've found several people complaining. Finally, after several hours of frustration and Googling, somehow I stumbled across great post
http://highaltitudedev.blogspot.com/2013/10/google-oauth2-with-jettyservlets.html
So I accomodated it to my needs.
This is how I build login request :
public static String getOauthUrlGoogle(HttpServletRequest request) {
String redirectUrl = "http://www.tralev.com/web/oauth2callback";
if (Html.isRunningLocally()) {
redirectUrl = "http://localhost:8080/TralevServer/web/oauth2callback";
}
StringBuilder oauthUrl = new StringBuilder();
oauthUrl.append("https://accounts.google.com/o/oauth2/auth")
.append("?client_id=").append(GOOGLE_CLIENT_ID) // the client id from the api console registration
.append("&response_type=code")
.append("&scope=profile%20email") // scope is the api permissions we are requesting
.append("&redirect_uri=").append(redirectUrl) // the servlet that google redirects to after authorization
.append("&state=").append(request.getSession().getId())
//.append("&access_type=offline") // here we are asking to access to user's data while they are not signed in
.append("&approval_prompt=force"); // this requires them to verify which account to use, if they are already signed in
return oauthUrl.toString();
}
And this is Servlet which performs the rest:
package com.tralev.server.web;
import commons.StringUtils;
import commons.UsualHtmlUtils;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
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 org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
/**
*
* @author mladen
*/
@WebServlet(name = "OAuth2CallbackServlet", urlPatterns = {"/web/oauth2callback"})
public class OAuth2CallbackServlet extends HttpServlet {
public static String GOOGLE_CLIENT_ID = "your id";
public static String GOOGLE_CLIENT_SECRET = "your secret";
public String getCallbackUrl() {
String redirectUrl = "http://www.tralev.com/web/oauth2callback";
if (Html.isRunningLocally()) {
redirectUrl = "http://localhost:8080/TralevServer/web/oauth2callback";
}
return redirectUrl;
}
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// google redirects with
//http://localhost:8089/callback?state=this_can_be_anything_to_help_correlate_the_response%3Dlike_session_id&code=4/ygE-kCdJ_pgwb1mKZq3uaTEWLUBd.slJWq1jM9mcUEnp6UAPFm0F2NQjrgwI&authuser=0&prompt=consent&session_state=a3d1eb134189705e9acf2f573325e6f30dd30ee4..d62c
// if the user denied access, we get back an error, ex
// error=access_denied&state=session%3Dpotatoes
if (req.getParameter("error") != null) {
Html.printPage(req, resp, "Error", StringUtils.toString(req.getParameter("error")));
} else {
// google returns a code that can be exchanged for a access token
String code = req.getParameter("code");
LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("code", code);
params.put("client_id", GOOGLE_CLIENT_ID);
params.put("client_secret", GOOGLE_CLIENT_SECRET);
params.put("redirect_uri", getCallbackUrl());
params.put("grant_type", "authorization_code");
// get the access token by post to Google
String body = post("https://accounts.google.com/o/oauth2/token", params);
// ex. returns
// {
// "access_token": "ya29.AHES6ZQS-BsKiPxdU_iKChTsaGCYZGcuqhm_A5bef8ksNoU",
// "token_type": "Bearer",
// "expires_in": 3600,
// "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA5ZmE5NmFjZWNkOGQyZWRjZmFiMjk0NDRhOTgyN2UwZmFiODlhYTYifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOiJ0cnVlIiwiZW1haWwiOiJhbmRyZXcucmFwcEBnbWFpbC5jb20iLCJhdWQiOiI1MDgxNzA4MjE1MDIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdF9oYXNoIjoieUpVTFp3UjVDX2ZmWmozWkNublJvZyIsInN1YiI6IjExODM4NTYyMDEzNDczMjQzMTYzOSIsImF6cCI6IjUwODE3MDgyMTUwMi5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImlhdCI6MTM4Mjc0MjAzNSwiZXhwIjoxMzgyNzQ1OTM1fQ.Va3kePMh1FlhT1QBdLGgjuaiI3pM9xv9zWGMA9cbbzdr6Tkdy9E-8kHqrFg7cRiQkKt4OKp3M9H60Acw_H15sV6MiOah4vhJcxt0l4-08-A84inI4rsnFn5hp8b-dJKVyxw1Dj1tocgwnYI03czUV3cVqt9wptG34vTEcV3dsU8",
// "refresh_token": "1/Hc1oTSLuw7NMc3qSQMTNqN6MlmgVafc78IZaGhwYS-o"
// }
JSONObject jsonObject = null;
// get the access token from json and request info from Google
try {
jsonObject = (JSONObject) new JSONParser().parse(body);
} catch (ParseException e) {
throw new RuntimeException("Unable to parse json " + body);
}
// google tokens expire after an hour, but since we requested offline access we can get a new token without user involvement via the refresh token
String accessToken = (String) jsonObject.get("access_token");
// you may want to store the access token in session
req.getSession().setAttribute("access_token", accessToken);
// get some info about the user with the access token
String json = get(new StringBuilder("https://www.googleapis.com/oauth2/v1/userinfo?access_token=").append(accessToken).toString());
try {
jsonObject = (JSONObject) new JSONParser().parse(json);
} catch (ParseException e) {
throw new RuntimeException("Unable to parse json " + body);
}
String email = (String) jsonObject.get("email");
String fullName = (String) jsonObject.get("name");
Logger.getLogger(this.getClass().getName()).log(Level.INFO, "email= {0} ,name={1}", new Object[]{email, fullName});
//do the rest stuff
}
}
// makes a GET request to url and returns body as a string
public String get(String url) throws ClientProtocolException, IOException {
return execute(new HttpGet(url));
}
// makes a POST request to url with form parameters and returns body as a string
public String post(String url, Map<String, String> formParameters) throws ClientProtocolException, IOException {
HttpPost request = new HttpPost(url);
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
for (String key : formParameters.keySet()) {
nvps.add(new BasicNameValuePair(key, formParameters.get(key)));
}
request.setEntity(new UrlEncodedFormEntity(nvps));
return execute(request);
}
// makes request and checks response code for 200
private String execute(HttpRequestBase request) throws ClientProtocolException, IOException {
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
HttpEntity entity = response.getEntity();
String body = EntityUtils.toString(entity);
if (response.getStatusLine().getStatusCode() != 200) {
throw new RuntimeException("Expected 200 but got " + response.getStatusLine().getStatusCode() + ", with body " + body);
}
return body;
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP <code>POST</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
private String getAfterLoginUrl(HttpServletRequest req) {
String afterLoginUrl = "http://www.tralev.com/web/main";
if (Html.isRunningLocally()) {
afterLoginUrl = "http://localhost:8080/TralevServer/web/main";
}
return afterLoginUrl;
}
}
Hope you'll find this useful or original post, I spent many hours looking into other overcomplex libraries and this was exactly what I was looking for.
Here is an example of servlet app that supports "login with Google".You can do OAuth2 to Google with servlets.
https://github.com/riversun/google-login-servlet-example-on-jetty.git
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.