หน้าเว็บ

วันพฤหัสบดีที่ 14 สิงหาคม พ.ศ. 2557

Google OAuth ใช้งาน Google+ : java


1. ขอ API Key

1.1. ไปที่ Google API Console https://code.google.com/apis/console/?noredirect แล้วไปที่เมนู Services


แล้วทำการ enable Google+ API


ถ้าไม่ enable เมื่อเขียน code จะได้รับ response ดังนี้
403: {
 "error": {
  "errors": [
   {
    "domain": "usageLimits",
    "reason": "accessNotConfigured",
    "message": "Access Not Configured. Please use Google Developers Console to activate the API for your project."
   }
  ],
  "code": 403,
  "message": "Access Not Configured. Please use Google Developers Console to activate the API for your project."
 }
}

1.2. ไปที่เมนู API Access


แล้วสร้าง api key  ด้วยการคลิกที่ปุ่ม Create another client ID


กรอกข้อมูล Application type 
ในที่นี้เลือก Web application แล้วใส่ Redirect URI ลงไปใน input box
เดี๋ยว google จะตัด Your site หรือ hostname ให้เองครับ  
แล้วคลิกปุ่ม Create client ID


เราจะได้ API Key ซึ่งประกอบไปด้วย Client ID และ Client Secret มา 1 ชุด  พร้อมทั้งแสดง Redirect URI ของ เว็บไซต์ที่ต้องการให้ redirect ไปหลังจาก authen เสร็จ

* หมายเหตุ : ที่ต้องกรอก Redirect URI เพราะเอาไว้ป้องกันการ hack แบบ man in the middle ที่ hacker ดักให้เปลี่ยนการ redirect ไปยัง page ที่ไม่ปลอดภัย

2. coding

2.1. มาที่โปรเจ็ค (ของผมเป็น maven) ให้เพิ่ม dependencies ไปที่ pom.xml ดังนี้
<dependency>
    <groupId>com.google.oauth-client</groupId>
    <artifactId>google-oauth-client</artifactId>
    <version>1.19.0</version>
</dependency>

<dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-plus</artifactId>
    <version>v1-rev137-1.19.0</version>
</dependency>
จากนั้น clean and build project ใหม่ เพื่อทำการ load dependencies จาก central repository (internet)

2.2. เขียน java
เขียน class Googles.java (utilities สำหรับการ authen)
อย่าลืมเอา Client ID, Client Secret และ Redirect URI มาแทนที่ด้วยน่ะครับ

package com.blogspot.na5cent.authen.social;

import com.google.api.client.auth.oauth2.CredentialRefreshListener;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import java.util.Arrays;
import java.util.List;

/**
 * @author redcrow
 * site : http://na5cent.blogspot.com/2014/08/google-oauth-google-java.html
 * create 15/08/2014
 */
public class Googles {

    private static final List<String> SCOPE = Arrays.asList(
            "https://www.googleapis.com/auth/plus.me",
            "https://www.googleapis.com/auth/plus.stream.write"
    );

    public static final String REDIRECT_URI = "YOUR_REDIRECT_URI";
    public static final String CLIENT_ID = "YOUR_CLIENT_ID";
    public static final String CLIENT_SECRET = "YOUR_CLIENT_SECRET";

    public static String getRedirectAuthenUrl() {
        return getCodeFlow()
                .newAuthorizationUrl()
                .setRedirectUri(REDIRECT_URI)
                .build();
    }

    public static GoogleAuthorizationCodeFlow getCodeFlow() {
        return new GoogleAuthorizationCodeFlow.Builder(
                new NetHttpTransport(),
                new JacksonFactory(),
                CLIENT_ID,
                CLIENT_SECRET,
                SCOPE
        ).build();
    }

    public static GoogleCredential getCredential(CredentialRefreshListener listener) {
        return new GoogleCredential.Builder()
                .setTransport(new NetHttpTransport())
                .setJsonFactory(new JacksonFactory())
                .setClientSecrets(CLIENT_ID, CLIENT_SECRET)
                .addRefreshListener(listener)
                .build();
    }
}
2. เขียน class GoogleAuthen.java  สำหรับ request authen
ซึ่งอาจจะเขียน Servlet ธรรมดาๆ ก็ได้  แต่ในที่นี้ผมขอเขียนเป็น Spring MVC น่ะครับ  (ขอไม่อธิบาย) ^_^
package com.blogspot.na5cent.authen.social;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.auth.oauth2.CredentialRefreshListener;
import com.google.api.client.auth.oauth2.TokenErrorResponse;
import com.google.api.client.auth.oauth2.TokenResponse;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.plus.Plus;
import com.google.api.services.plus.model.Person;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author redcrow
 * site : http://na5cent.blogspot.com/2014/08/google-oauth-google-java.html
 * create 15/08/2014
 */
@Controller
public class GoogleAuthen {

    private static final Logger LOG = LoggerFactory.getLogger(GoogleAuthen.class);

    @ResponseBody
    @RequestMapping(value = "/authen/google", method = RequestMethod.GET)
    public String signIn(HttpServletResponse response) throws Exception {
        response.sendRedirect(Googles.getRedirectAuthenUrl());
        return null;
    }

    @ResponseBody
    @RequestMapping(value = "/authen/google/done", method = RequestMethod.GET)
    public String signInCallback(HttpServletRequest request) throws Exception {
        GoogleCredential credential = getCredential();
        credential.setFromTokenResponse(getToken(request.getParameter("code")));
        credential.refreshToken();

        Plus plus = buildGooglePlus(credential);
        printGooglePlusInfo(plus);

        return null;
    }

    private GoogleCredential getCredential() {
        return Googles.getCredential(new CredentialRefreshListener() {
            @Override
            public void onTokenResponse(Credential credential, TokenResponse tokenResponse) {
                LOG.debug("Credential was refreshed successfully.");
            }

            @Override
            public void onTokenErrorResponse(Credential credential, TokenErrorResponse tokenErrorResponse) {
                LOG.warn("Credential was not refreshed successfully. Redirect to error page or login screen.");
            }
        });
    }

    private GoogleTokenResponse getToken(String authCode) throws IOException {
        return Googles.getCodeFlow()
                .newTokenRequest(authCode)
                .setRedirectUri(Googles.REDIRECT_URI)
                .execute();
    }

    private Plus buildGooglePlus(GoogleCredential credential) {
        return new Plus.Builder(
                new NetHttpTransport(),
                new JacksonFactory(),
                credential
        ).build();
    }

    private void printGooglePlusInfo(Plus plus) throws IOException {
        Person me = plus.people().get("me").execute();

        LOG.debug("id --> {}", me.getId());
        LOG.debug("display name --> {}", me.getDisplayName());
        LOG.debug("image url --> {}", me.getImage().getUrl());
        LOG.debug("profile url --> {}", me.getUrl());
    }
}

2.3 ลองเข้า URL browser เป็น http://localhost:8080/authen/google  หรืออาจจะทำเป็น link เพื่อให้คลิกเข้าไปก็ได้  (ตาม request mapping หรือ servlet ที่เขียนไว้) มันจะ redirect ไปยังหน้า authen ของ google ครับ  ซึ่งเมื่อเรา authen และ authorize เสร็จ  ก็จะถูก google redirect กลับมาตาม oauth flow ไปยัง Redirect URI ที่เราเขียนไว้  ซึ่งก็คือ http://localhost:8080/authen/google/done  นั่นเอง

ข้อมูลจะแสดงผลลัพธ์ออกใน log ของ application server ที่เราเขียนไว้ใน method printGooglePlusInfo ดังนี้


หวังว่าบทความนี้  คงพอเป็นประโยชน์สำหรับ java developer น่ะครับ :-) 
เรียนรู้ เพิ่มเติมได้ที่ https://developers.google.com/+/?hl=th

1 ความคิดเห็น:

  1. เดี่ยวนี้ยังสามารถทำได้อยู่ไหมครับ
    ผมทำ php ขึ้น error permission ไม่รู้ต้องเซตอย่างไร ดูใน report มา connect กันได้อยู่แต่ขึ้น status 403

    หากจะคิดค่าจ้างคิดเท่าไหร่ครับ

    ตอบลบ