OAuth Login Solution(2)Scala and Callback URLs

OAuth Login Solution(2)Scala and Callback URLs

OauthService.scala Codes to Generate AuthURL/Fetch RefreshToken/Fetch Profile
package services
import java.util.Arrays;
import com.google.api.client.googleapis.auth.oauth2.{GoogleTokenResponse, GoogleAuthorizationCodeRequestUrl}
import com.jobs2careers.util.IncludeLogger
import models.{ AccountProfileResponse}
import play.api.libs.json.Json
import play.api.libs.ws.{WSResponse, WS}
import utils.IncludeOauthConfig
import scala.concurrent.duration._
import scala.concurrent.Await
import scala.concurrent.Future
import play.api.Play.current
import com.google.api.client.auth.oauth2.Credential
import com.google.api.client.auth.oauth2.TokenResponse
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow
import com.google.api.client.http.GenericUrl
import com.google.api.client.http.HttpRequest
import com.google.api.client.http.HttpRequestFactory
import com.google.api.client.http.HttpTransport
import com.google.api.client.http.javanet.NetHttpTransport
import com.google.api.client.json.JsonFactory
import com.google.api.client.json.jackson2.JacksonFactory
import com.google.api.services.gmail.GmailScopes

object OauthService extends IncludeOauthConfig with IncludeLogger{
  implicit val accountProfileResponseWrites = Json.writes[AccountProfileResponse]
  implicit val accountProfileResponseReads = Json.reads[AccountProfileResponse]

  val callbackURL = OAUTH_CALLBACK_URI
  val USER_INFO_URL = "https://www.googleapis.com/auth/userinfo.profile"
  val EMAIL_INFO_URL = "https://www.googleapis.com/auth/userinfo.email"
  val USER_PROFILE_URL = "https://www.googleapis.com/oauth2/v1/userinfo"
  val JSON_FACTORY:JsonFactory = new JacksonFactory()
  val HTTP_TRANSPORT:HttpTransport = new NetHttpTransport()

  def generateAuthURL(accountCode:String):String = {
    val flow:GoogleAuthorizationCodeFlow = new GoogleAuthorizationCodeFlow.Builder(
      HTTP_TRANSPORT, JSON_FACTORY, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET,
      Arrays.asList(GmailScopes.MAIL_GOOGLE_COM, GmailScopes.GMAIL_READONLY, USER_INFO_URL, EMAIL_INFO_URL))
      .setAccessType("offline")
      .setApprovalPrompt("force")
      .build()
    val url:GoogleAuthorizationCodeRequestUrl = flow.newAuthorizationUrl()
    val url_str =  url.setRedirectUri(callbackURL).setState(accountCode).build()
    //url_str = url_str + "&[email protected]";
    return url_str
  }

  def fetchRefreshToken(accessToken:String):String = {
    val flow:GoogleAuthorizationCodeFlow = new GoogleAuthorizationCodeFlow.Builder(
      HTTP_TRANSPORT, JSON_FACTORY, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET,
      Arrays.asList(GmailScopes.MAIL_GOOGLE_COM, GmailScopes.GMAIL_READONLY, USER_INFO_URL, EMAIL_INFO_URL))
      .setAccessType("offline")
      .setApprovalPrompt("force")
      .build()
    val response:GoogleTokenResponse = flow.newTokenRequest(accessToken)
      .setRedirectUri(callbackURL).execute()
    val refreshToken = response.getRefreshToken()
    logger.debug("Refresh token system get = " + refreshToken)
    return refreshToken
  }

  def fetchEmail(refreshToken:String): Option[String] = {
    val flow:GoogleAuthorizationCodeFlow = new GoogleAuthorizationCodeFlow.Builder(
      HTTP_TRANSPORT, JSON_FACTORY, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET,
      Arrays.asList(GmailScopes.MAIL_GOOGLE_COM, GmailScopes.GMAIL_READONLY, USER_INFO_URL, EMAIL_INFO_URL))
      .setAccessType("offline")
      .setApprovalPrompt("force")
      .build()
    logger.debug("Refresh Token = " + refreshToken)
    val tokenResponse:TokenResponse = new TokenResponse()
    tokenResponse.setRefreshToken(refreshToken)
    val credential:Credential = flow.createAndStoreCredential(tokenResponse, null)
    val requestFactory:HttpRequestFactory = HTTP_TRANSPORT.createRequestFactory(credential)
    // Make an authenticated request
    val  genericUrl:GenericUrl = new GenericUrl(USER_INFO_URL)
    val  request:HttpRequest = requestFactory.buildGetRequest(genericUrl)
    request.getHeaders().setContentType("application/json")
    request.execute()
    val accessToken = credential.getAccessToken()
    logger.debug("System get the new Access Token = " + accessToken)
//    {
//      "id": "114122167329329897934",
//      "email": “[email protected]",
//      "verified_email": true,
//      "name": “Sillycat Mobile",
//      "given_name": “sillycat",
//      "family_name": "Mobile",
//      "picture": "https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/photo.jpg",
//      "locale": "en",
//      "hd": “gmail.com"
//    }
    val url = USER_PROFILE_URL + "?alt=json&access_token=" + accessToken
    logger.debug("URL = " + url)
    val future:Future[WSResponse] = WS.url(url).get()
    val result = Await.result(future, 20 seconds)
    logger.debug("Fetching the profile response = " + result.json + " accessToken = " + accessToken)
    val email = result.json.asOpt[AccountProfileResponse].map { profile =>
      logger.info("Fetching the profile information = " + profile)
      profile.email
    }
    return email
  }
}

The Callback URL who handle the Callback
  def addSource = Action { request =>

    logger.debug("The request body = " + request.body)

    val accessToken = request.getQueryString("code").getOrElse("")
    val accountCode = request.getQueryString("state").getOrElse("")

    logger.debug("First access token system get = " + accessToken)

    if(accessToken.isEmpty || accountCode.isEmpty){
      val warn_msg = "Callback add source fail, request params accountCode = " + accountCode
      logger.warn(warn_msg)
      BadRequest(Json.obj("status" -> "Fail", "message" -> warn_msg))
    }else{
      val refreshToken = OauthService.fetchRefreshToken(accessToken)
      val email = OauthService.fetchEmail(refreshToken).getOrElse("")
      if(email.isEmpty){
        val warn_msg = "Callback add source fail, fail to fetch email with refreshToken."
        logger.warn(warn_msg)
        BadRequest(Json.obj("status" -> "Fail", "message" -> warn_msg))
      }else{
        //call actor to ContextIO to add source
       sillycatIOthrottler ! AccountSourceMessage(
          accountCode, //accountCode
          email, //email system fetch from profile
          email, //username, same as email for google
          refreshToken //refreshToken
        )
        Ok(Json.obj("status" -> "OK"))
      }
    }
  }

The dependencies in build.sbt
"com.google.api-client" % "google-api-client" % "1.20.0",
"com.google.oauth-client" % "google-oauth-client" % "1.20.0",
"com.google.apis" % "google-api-services-gmail" % "v1-rev36-1.20.0",

References:
http://sillycat.iteye.com/blog/2274258

你可能感兴趣的:(OAuth Login Solution(2)Scala and Callback URLs)