mercredi 25 mars 2015

Spring MVC : Sign-in with google+ by using API

I am working on a Spring-MVC application in which I would like to integrate Google+ signin functionality. Before this, with some help form nice people on SO, I managed to implement Google Calendar functionality.


Now, when I am trying to use Google+ sign in, I have 2 options, either use PHP code, or Javascript coupled with some other backend options.


My point is, Google Calendar implementation also required authorization by the user, but I was able to do that purely in Java, while I am having trouble doing that in Java as I cannot find any relevant code. I would just like to call the java method, which opens a new tab in browser, user clicks accept, and I am redirected to URI(Similar to Google calendar I will post below)


Can anyone help me understand why the only code I found runs in embedded server, and I cannot get it running without it. Thanks a lot.


Calendar code :



public void authorizeAndTest(){

try {
httpTransport = new NetHttpTransport();
dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
Credential credential = authorize();

client = new com.google.api.services.calendar.Calendar.Builder(httpTransport,JSON_FACTORY,credential).setApplicationName(APPLICATION_NAME).build();
showCalenders();
addCalendarsUsingBatch();
Calendar calendar = addCalendar();
updateCalendar(calendar);
addEvent(calendar);
showEvents(calendar);
deleteCalendarInBatch();
deleteCalendar(calendar);
} catch (Exception e) {
e.printStackTrace();
}
}

private static Credential authorize() throws Exception{

AuthorizationCodeFlow codeFlow = new GoogleAuthorizationCodeFlow(httpTransport,JSON_FACTORY,
"clientid",
"clientsecret", Collections.singleton(CalendarScopes.CALENDAR));


return new AuthorizationCodeInstalledApp(codeFlow,new LocalServerReceiver()).authorize("user@gmail.com");
}


Now the above code works like a charm, I just call my controller method, which calls authorizeAndTest, no problems at all, it opens a tab, I click accept, and it starts the process.


Welcome to Google+ sign in : Below code is from sample :



public static void main(String[] args) throws Exception {
Server server = new Server(4567);
ServletHandler servletHandler = new ServletHandler();
SessionHandler sessionHandler = new SessionHandler();
sessionHandler.setHandler(servletHandler);
server.setHandler(sessionHandler);
servletHandler.addServletWithMapping(ConnectServlet.class, "/connect");
servletHandler.addServletWithMapping(DisconnectServlet.class, "/disconnect");
servletHandler.addServletWithMapping(PeopleServlet.class, "/people");
servletHandler.addServletWithMapping(MainServlet.class, "/");
server.start();
server.join();
}

public static class MainServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// This check prevents the "/" handler from handling all requests by default
if (!"/".equals(request.getServletPath())) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}

response.setContentType("text/html");
try {
// Create a state token to prevent request forgery.
// Store it in the session for later validation.
String state = new BigInteger(130, new SecureRandom()).toString(32);
request.getSession().setAttribute("state", state);
// Fancy way to read index.html into memory, and set the client ID
// and state values in the HTML before serving it.
response.getWriter().print(new Scanner(new File("index.html"), "UTF-8")
.useDelimiter("\\A").next()
.replaceAll("[{]{2}\\s*CLIENT_ID\\s*[}]{2}", CLIENT_ID)
.replaceAll("[{]{2}\\s*STATE\\s*[}]{2}", state)
.replaceAll("[{]{2}\\s*APPLICATION_NAME\\s*[}]{2}",
APPLICATION_NAME)
.toString());
response.setStatus(HttpServletResponse.SC_OK);
} catch (FileNotFoundException e) {
// When running the quickstart, there was some path issue in finding
// index.html. Double check the quickstart guide.
e.printStackTrace();
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.getWriter().print(e.toString());
}
}
}


So, I cannot call classes in Controller as far as I know, and the dependency over index.html is a problem, so I modified the code a bit.


GoogleSignin.java



public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// This check prevents the "/" handler from handling all requests by default
if (!"/".equals(request.getServletPath())) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}

response.setContentType("text/html");
try {
String state = new BigInteger(130, new SecureRandom()).toString(32);
request.getSession().setAttribute("state", state);
response.setStatus(HttpServletResponse.SC_OK);
} catch (Exception e) {
// When running the quickstart, there was some path issue in finding
// index.html. Double check the quickstart guide.
e.printStackTrace();
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.getWriter().print(e.toString());
}
}

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/json");


String tokenData = (String) request.getSession().getAttribute("token");
System.out.println("Tokendata is "+tokenData);
if (tokenData != null) {
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().print(GSON.toJson("Current user is already connected."));
return;
}

if (!request.getParameter("state").equals(request.getSession().getAttribute("state"))) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().print(GSON.toJson("Invalid state parameter."));
return;
}

System.out.println("Request is "+request.toString());
ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
getContent(request.getInputStream(), resultStream);
String code = new String(resultStream.toByteArray(), "UTF-8");

try {
GoogleTokenResponse tokenResponse =
new GoogleAuthorizationCodeTokenRequest(TRANSPORT, JSON_FACTORY,
CLIENT_ID, CLIENT_SECRET, code, "postmessage").execute();

GoogleIdToken idToken = tokenResponse.parseIdToken();
String gplusId = idToken.getPayload().getSubject();
System.out.println("Response from google plus is "+gplusId);

request.getSession().setAttribute("token", tokenResponse.toString());
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().print(GSON.toJson("Successfully connected user."));
} catch (TokenResponseException e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().print(GSON.toJson("Failed to upgrade the authorization code."));
} catch (IOException e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().print(GSON.toJson("Failed to read token data from Google. " +
e.getMessage()));
}
}


Controller code goes like this :



@RequestMapping(value = "/authorize")
public String googleReplyManagment(HttpServletRequest request, HttpServletResponse response){
//OAuth oAuth = new OAuth();
//oAuth.authorizeAndTest();
response.setContentType("application/json");

GoogleSignIn googleSignIn = new GoogleSignIn();
try {
googleSignIn.doGet(request,response);
googleSignIn.doPost(request,response);

} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/";
}


And I get the following error :


Error code :



java.lang.NullPointerException
at com.journaldev.spring.utility.GoogleSignIn.doPost(GoogleSignIn.java:127)
at com.journaldev.spring.controller.PersonController.googleReplyManagment(PersonController.java:1453)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)


What can I do about this, any help would be nice. Thanks alot.


Aucun commentaire:

Enregistrer un commentaire