สร้างเครื่องจัดการโค้ดเรียกกลับการให้สิทธิ์

เอกสารนี้อธิบายวิธีใช้ตัวแฮนเดิลการเรียกกลับการให้สิทธิ์ OAuth 2.0 โดยใช้เซิร์ฟเล็ต Java ผ่านตัวอย่างเว็บแอปพลิเคชันที่แสดงงานของผู้ใช้โดยใช้ Google Tasks API แอปพลิเคชันตัวอย่างจะขอสิทธิ์เข้าถึง Google Tasks ของผู้ใช้ก่อน จากนั้นจะแสดงงานของผู้ใช้ในรายการงานเริ่มต้น

ผู้ชม

เอกสารนี้ปรับให้เหมาะกับผู้ที่คุ้นเคยกับสถาปัตยกรรมเว็บแอปพลิเคชัน Java และ J2EE ขอแนะนำให้มีความรู้เกี่ยวกับขั้นตอนการให้สิทธิ์ OAuth 2.0 บ้าง

เนื้อหา

หากต้องการมีตัวอย่างที่ใช้งานได้อย่างสมบูรณ์ คุณต้องทำตามขั้นตอนต่อไปนี้

ประกาศการแมปเซิร์ฟเล็ตในไฟล์ web.xml

เราจะใช้เซิร์วิต 2 รายการในแอปพลิเคชัน ดังนี้

  • PrintTasksTitlesServlet (แมปกับ /): จุดแรกเข้าของแอปพลิเคชันที่จัดการการตรวจสอบสิทธิ์ของผู้ใช้ และจะแสดงงานของผู้ใช้
  • OAuthCodeCallbackHandlerServlet (แมปกับ /oauth2callback): แคล็กแบ็ก OAuth 2.0 ที่จัดการการตอบกลับจากปลายทางการให้สิทธิ์ OAuth

ด้านล่างนี้คือไฟล์ web.xml ซึ่งแมปเซิร์ฟเลต 2 รายการนี้กับ URL ในแอปพลิเคชัน

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

 <servlet>
   <servlet-name>PrintTasksTitles</servlet-name>
   <servlet-class>com.google.oauthsample.PrintTasksTitlesServlet</servlet-class>
 </servlet>

 <servlet-mapping>
   <servlet-name>PrintTasksTitles</servlet-name>
   <url-pattern>/</url-pattern>
 </servlet-mapping>

 <servlet>
   <servlet-name>OAuthCodeCallbackHandlerServlet</servlet-name>
   <servlet-class>com.google.oauthsample.OAuthCodeCallbackHandlerServlet</servlet-class>
 </servlet>

 <servlet-mapping>
   <servlet-name>OAuthCodeCallbackHandlerServlet</servlet-name>
   <url-pattern>/oauth2callback</url-pattern>
 </servlet-mapping>

</web-app>
ไฟล์ /WEB-INF/web.xml

ตรวจสอบสิทธิ์ผู้ใช้ในระบบและขอสิทธิ์เข้าถึงงาน

ผู้ใช้เข้าสู่แอปพลิเคชันผ่าน URL รูท "/" ซึ่งแมปกับ Servlet PrintTaskListsTitlesServlet Servlet ดังกล่าวจะดําเนินการต่อไปนี้

  • ตรวจสอบว่าผู้ใช้ผ่านการตรวจสอบสิทธิ์ในระบบหรือไม่
  • หากผู้ใช้ไม่ได้รับการตรวจสอบสิทธิ์ ระบบจะเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าการตรวจสอบสิทธิ์
  • หากผู้ใช้ได้รับการตรวจสอบสิทธิ์ เราจะตรวจสอบว่ามีโทเค็นรีเฟรชอยู่ในพื้นที่เก็บข้อมูลของเราหรือไม่ ซึ่งจัดการโดย OAuthTokenDao ด้านล่าง หากไม่มีโทเค็นรีเฟรชที่จัดเก็บไว้สำหรับผู้ใช้ แสดงว่าผู้ใช้ยังไม่ได้ให้สิทธิ์แอปพลิเคชันเข้าถึงงาน ในกรณีนี้ ระบบจะเปลี่ยนเส้นทางผู้ใช้ไปยังปลายทางการให้สิทธิ์ OAuth 2.0 ของ Google
วิธีติดตั้งใช้งานมีดังนี้

package com.google.oauthsample;

import ...

/**
 * Simple sample Servlet which will display the tasks in the default task list of the user.
 */
@SuppressWarnings("serial")
public class PrintTasksTitlesServlet extends HttpServlet {

  /**
   * The OAuth Token DAO implementation, used to persist the OAuth refresh token.
   * Consider injecting it instead of using a static initialization. Also we are
   * using a simple memory implementation as a mock. Change the implementation to
   * using your database system.
   */
  public static OAuthTokenDao oauthTokenDao = new OAuthTokenDaoMemoryImpl();

  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    // Getting the current user
    // This is using App Engine's User Service but you should replace this to
    // your own user/login implementation
    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();

    // If the user is not logged-in it is redirected to the login service, then back to this page
    if (user == null) {
      resp.sendRedirect(userService.createLoginURL(getFullRequestUrl(req)));
      return;
    }

    // Checking if we already have tokens for this user in store
    AccessTokenResponse accessTokenResponse = oauthTokenDao.getKeys(user.getEmail());

    // If we don't have tokens for this user
    if (accessTokenResponse == null) {
      OAuthProperties oauthProperties = new OAuthProperties();
      // Redirect to the Google OAuth 2.0 authorization endpoint
      resp.sendRedirect(new GoogleAuthorizationRequestUrl(oauthProperties.getClientId(),
          OAuthCodeCallbackHandlerServlet.getOAuthCodeCallbackHandlerUrl(req), oauthProperties
              .getScopesAsString()).build());
      return;
    }
  }

  /**
   * Construct the request's URL without the parameter part.
   *
   * @param req the HttpRequest object
   * @return The constructed request's URL
   */
  public static String getFullRequestUrl(HttpServletRequest req) {
    String scheme = req.getScheme() + "://";
    String serverName = req.getServerName();
    String serverPort = (req.getServerPort() == 80) ? "" : ":" + req.getServerPort();
    String contextPath = req.getContextPath();
    String servletPath = req.getServletPath();
    String pathInfo = (req.getPathInfo() == null) ? "" : req.getPathInfo();
    String queryString = (req.getQueryString() == null) ? "" : "?" + req.getQueryString();
    return scheme + serverName + serverPort + contextPath + servletPath + pathInfo + queryString;
  }
}
ไฟล์ PrintTasksTitlesServlet.java

หมายเหตุ: การใช้งานข้างต้นใช้ไลบรารี App Engine บางรายการ ซึ่งใช้เพื่อลดความซับซ้อน หากคุณกำลังพัฒนาแอปสำหรับแพลตฟอร์มอื่น คุณสามารถใช้อินเทอร์เฟซ UserService อีกครั้งซึ่งจัดการการตรวจสอบสิทธิ์ของผู้ใช้

แอปพลิเคชันใช้ DAO เพื่อเก็บรักษาและเข้าถึงโทเค็นการให้สิทธิ์ของผู้ใช้ ด้านล่างนี้คืออินเทอร์เฟซ OAuthTokenDao และการใช้งานจำลอง (ในหน่วยความจำ) OAuthTokenDaoMemoryImpl ที่ใช้ในตัวอย่างนี้

package com.google.oauthsample;

import com.google.api.client.auth.oauth2.draft10.AccessTokenResponse;

/**
 * Allows easy storage and access of authorization tokens.
 */
public interface OAuthTokenDao {

  /**
   * Stores the given AccessTokenResponse using the {@code username}, the OAuth
   * {@code clientID} and the tokens scopes as keys.
   *
   * @param tokens The AccessTokenResponse to store
   * @param userName The userName associated wit the token
   */
  public void saveKeys(AccessTokenResponse tokens, String userName);

  /**
   * Returns the AccessTokenResponse stored for the given username, clientId and
   * scopes. Returns {@code null} if there is no AccessTokenResponse for this
   * user and scopes.
   *
   * @param userName The username of which to get the stored AccessTokenResponse
   * @return The AccessTokenResponse of the given username
   */
  public AccessTokenResponse getKeys(String userName);
}
ไฟล์ OAuthTokenDao.java
package com.google.oauthsample;

import com.google.api.client.auth.oauth2.draft10.AccessTokenResponse;
...

/**
 * Quick and Dirty memory implementation of {@link OAuthTokenDao} based on
 * HashMaps.
 */
public class OAuthTokenDaoMemoryImpl implements OAuthTokenDao {

  /** Object where all the Tokens will be stored */
  private static Map<String, AccessTokenResponse> tokenPersistance = new HashMap<String, AccessTokenResponse>();

  public void saveKeys(AccessTokenResponse tokens, String userName) {
    tokenPersistance.put(userName, tokens);
  }

  public AccessTokenResponse getKeys(String userName) {
    return tokenPersistance.get(userName);
  }
}
ไฟล์ OAuthTokenDaoMemoryImpl.java

นอกจากนี้ ระบบจะจัดเก็บข้อมูลเข้าสู่ระบบ OAuth 2.0 ของแอปพลิเคชันในไฟล์พร็อพเพอร์ตี้ด้วย หรือจะกำหนดค่าเหล่านี้เป็นค่าคงที่ในคลาส Java ก็ได้ แต่นี่คือคลาส OAuthProperties และไฟล์ oauth.properties ที่ใช้ในตัวอย่างนี้

package com.google.oauthsample;

import ...

/**
 * Object representation of an OAuth properties file.
 */
public class OAuthProperties {

  public static final String DEFAULT_OAUTH_PROPERTIES_FILE_NAME = "oauth.properties";

  /** The OAuth 2.0 Client ID */
  private String clientId;

  /** The OAuth 2.0 Client Secret */
  private String clientSecret;

  /** The Google APIs scopes to access */
  private String scopes;

  /**
   * Instantiates a new OauthProperties object reading its values from the
   * {@code OAUTH_PROPERTIES_FILE_NAME} properties file.
   *
   * @throws IOException IF there is an issue reading the {@code propertiesFile}
   * @throws OauthPropertiesFormatException If the given {@code propertiesFile}
   *           is not of the right format (does not contains the keys {@code
   *           clientId}, {@code clientSecret} and {@code scopes})
   */
  public OAuthProperties() throws IOException {
    this(OAuthProperties.class.getResourceAsStream(DEFAULT_OAUTH_PROPERTIES_FILE_NAME));
  }

  /**
   * Instantiates a new OauthProperties object reading its values from the given
   * properties file.
   *
   * @param propertiesFile the InputStream to read an OAuth Properties file. The
   *          file should contain the keys {@code clientId}, {@code
   *          clientSecret} and {@code scopes}
   * @throws IOException IF there is an issue reading the {@code propertiesFile}
   * @throws OAuthPropertiesFormatException If the given {@code propertiesFile}
   *           is not of the right format (does not contains the keys {@code
   *           clientId}, {@code clientSecret} and {@code scopes})
   */
  public OAuthProperties(InputStream propertiesFile) throws IOException {
    Properties oauthProperties = new Properties();
    oauthProperties.load(propertiesFile);
    clientId = oauthProperties.getProperty("clientId");
    clientSecret = oauthProperties.getProperty("clientSecret");
    scopes = oauthProperties.getProperty("scopes");
    if ((clientId == null) || (clientSecret == null) || (scopes == null)) {
      throw new OAuthPropertiesFormatException();
    }
  }

  /**
   * @return the clientId
   */
  public String getClientId() {
    return clientId;
  }

  /**
   * @return the clientSecret
   */
  public String getClientSecret() {
    return clientSecret;
  }

  /**
   * @return the scopes
   */
  public String getScopesAsString() {
    return scopes;
  }

  /**
   * Thrown when the OAuth properties file was not at the right format, i.e not
   * having the right properties names.
   */
  @SuppressWarnings("serial")
  public class OAuthPropertiesFormatException extends RuntimeException {
  }
}
ไฟล์ OAuthProperties.java

ด้านล่างนี้คือไฟล์ oauth.properties ซึ่งมีข้อมูลเข้าสู่ระบบ OAuth 2.0 ของแอปพลิเคชัน คุณต้องเปลี่ยนค่าด้านล่างด้วยตนเอง

# Client ID and secret. They can be found in the APIs console.
clientId=1234567890.apps.googleusercontent.com
clientSecret=aBcDeFgHiJkLmNoPqRsTuVwXyZ
# API scopes. Space separated.
scopes=https://www.googleapis.com/auth/tasks
ไฟล์ oauth.properties

รหัสไคลเอ็นต์ OAuth 2.0 และรหัสลับไคลเอ็นต์จะระบุแอปพลิเคชันของคุณและอนุญาตให้ Tasks API ใช้ตัวกรองและกฎโควต้าที่กำหนดไว้สำหรับแอปพลิเคชัน รหัสไคลเอ็นต์และรหัสลับจะอยู่ในคอนโซล Google API เมื่ออยู่ในคอนโซล คุณจะต้องดำเนินการต่อไปนี้

  • สร้างหรือเลือกโปรเจ็กต์
  • เปิดใช้ Tasks API โดยสลับสถานะ Tasks API เป็นเปิดในรายการบริการ
  • ในส่วนการเข้าถึง API ให้สร้างรหัสไคลเอ็นต์ OAuth 2.0 หากยังไม่ได้สร้าง
  • ตรวจสอบว่า URL ตัวแฮนเดิลการเรียกกลับรหัส OAuth 2.0 ของโปรเจ็กต์ได้รับการลงทะเบียน/อนุญาตพิเศษใน URI การเปลี่ยนเส้นทาง ตัวอย่างเช่น ในโปรเจ็กต์ตัวอย่างนี้ คุณจะต้องลงทะเบียน https://www.example.com/oauth2callback หากเว็บแอปพลิเคชันแสดงจากโดเมน https://www.example.com

URI การเปลี่ยนเส้นทางในคอนโซล API
URI การเปลี่ยนเส้นทางในคอนโซล API

รอรหัสการให้สิทธิ์จากปลายทางการให้สิทธิ์ของ Google

ในกรณีที่ผู้ใช้ยังไม่ได้ให้สิทธิ์แอปพลิเคชันเข้าถึงงานของตน และระบบจึงเปลี่ยนเส้นทางไปยังปลายทางการให้สิทธิ์ OAuth 2.0 ของ Google ผู้ใช้จะเห็นกล่องโต้ตอบการให้สิทธิ์จาก Google ซึ่งขอให้ผู้ใช้ให้สิทธิ์แอปพลิเคชันเข้าถึงงาน ดังนี้

กล่องโต้ตอบการให้สิทธิ์ของ Google
กล่องโต้ตอบการให้สิทธิ์ของ Google

หลังจากให้สิทธิ์หรือปฏิเสธการเข้าถึงแล้ว ระบบจะเปลี่ยนเส้นทางผู้ใช้กลับไปยังตัวแฮนเดิลการเรียกกลับโค้ด OAuth 2.0 ซึ่งระบุไว้เป็นการเปลี่ยนเส้นทาง/การเรียกกลับเมื่อสร้าง URL การให้สิทธิ์ของ Google

new GoogleAuthorizationRequestUrl(oauthProperties.getClientId(),
      OAuthCodeCallbackHandlerServlet.getOAuthCodeCallbackHandlerUrl(req), oauthProperties
          .getScopesAsString()).build()

แฮนเดิลการเรียกกลับรหัส OAuth 2.0 - OAuthCodeCallbackHandlerServlet - จะจัดการการเปลี่ยนเส้นทางจากปลายทาง OAuth 2.0 ของ Google การจัดการมี 2 กรณีดังนี้

  • ผู้ใช้ให้สิทธิ์เข้าถึง: แยกวิเคราะห์คําขอเพื่อรับรหัส OAuth 2.0 จากพารามิเตอร์ URL
  • ผู้ใช้ถูกปฏิเสธการเข้าถึง: แสดงข้อความต่อผู้ใช้

package com.google.oauthsample;

import ...

/**
 * Servlet handling the OAuth callback from the authentication service. We are
 * retrieving the OAuth code, then exchanging it for a refresh and an access
 * token and saving it.
 */
@SuppressWarnings("serial")
public class OAuthCodeCallbackHandlerServlet extends HttpServlet {

  /** The name of the Oauth code URL parameter */
  public static final String CODE_URL_PARAM_NAME = "code";

  /** The name of the OAuth error URL parameter */
  public static final String ERROR_URL_PARAM_NAME = "error";

  /** The URL suffix of the servlet */
  public static final String URL_MAPPING = "/oauth2callback";

  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    // Getting the "error" URL parameter
    String[] error = req.getParameterValues(ERROR_URL_PARAM_NAME);

    // Checking if there was an error such as the user denied access
    if (error != null && error.length > 0) {
      resp.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE, "There was an error: \""+error[0]+"\".");
      return;
    }
    // Getting the "code" URL parameter
    String[] code = req.getParameterValues(CODE_URL_PARAM_NAME);

    // Checking conditions on the "code" URL parameter
    if (code == null || code.length == 0) {
      resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "The \"code\" URL parameter is missing");
      return;
    }
  }

  /**
   * Construct the OAuth code callback handler URL.
   *
   * @param req the HttpRequest object
   * @return The constructed request's URL
   */
  public static String getOAuthCodeCallbackHandlerUrl(HttpServletRequest req) {
    String scheme = req.getScheme() + "://";
    String serverName = req.getServerName();
    String serverPort = (req.getServerPort() == 80) ? "" : ":" + req.getServerPort();
    String contextPath = req.getContextPath();
    String servletPath = URL_MAPPING;
    String pathInfo = (req.getPathInfo() == null) ? "" : req.getPathInfo();
    return scheme + serverName + serverPort + contextPath + servletPath + pathInfo;
  }
}
ไฟล์ OAuthCodeCallbackHandlerServlet.java

เปลี่ยนรหัสการให้สิทธิ์เป็นโทเค็นการรีเฟรชและโทเค็นการเข้าถึง

จากนั้น OAuthCodeCallbackHandlerServlet จะแลกเปลี่ยนรหัส Auth 2.0 กับโทเค็นการรีเฟรชและโทเค็นการเข้าถึง เก็บไว้ในที่เก็บข้อมูล และเปลี่ยนเส้นทางผู้ใช้กลับไปที่ URL ของ PrintTaskListsTitlesServlet ดังนี้

โค้ดที่เพิ่มลงในไฟล์ด้านล่างจะไฮไลต์ไวยากรณ์ ส่วนโค้ดที่มีอยู่แล้วจะเป็นสีเทา

package com.google.oauthsample;

import ...

/**
 * Servlet handling the OAuth callback from the authentication service. We are
 * retrieving the OAuth code, then exchanging it for a refresh and an access
 * token and saving it.
 */
@SuppressWarnings("serial")
public class OAuthCodeCallbackHandlerServlet extends HttpServlet {

  /** The name of the Oauth code URL parameter */
  public static final String CODE_URL_PARAM_NAME = "code";

  /** The name of the OAuth error URL parameter */
  public static final String ERROR_URL_PARAM_NAME = "error";

  /** The URL suffix of the servlet */
  public static final String URL_MAPPING = "/oauth2callback";
/** The URL to redirect the user to after handling the callback. ลองพิจารณา * บันทึกข้อมูลนี้ในคุกกี้ก่อนที่จะเปลี่ยนเส้นทางผู้ใช้ไปยัง URL การให้สิทธิ์ของ Google หากมี URL หลายรายการที่เป็นไปได้ที่จะเปลี่ยนเส้นทางผู้ใช้ */ public static final String REDIRECT_URL = "/"; /** The OAuth Token DAO implementation. ลองใช้การแทรกแทนการใช้การเริ่มต้นแบบคงที่ * นอกจากนี้ เรายังใช้หน่วยความจําแบบง่าย ๆ เป็นตัวจำลอง * เปลี่ยนการติดตั้งใช้งานเป็นการใช้ระบบฐานข้อมูล */ public static OAuthTokenDao oauthTokenDao = new OAuthTokenDaoMemoryImpl();
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    // Getting the "error" URL parameter
    String[] error = req.getParameterValues(ERROR_URL_PARAM_NAME);

    // Checking if there was an error such as the user denied access
    if (error != null && error.length > 0) {
      resp.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE, "There was an error: \""+error[0]+"\".");
      return;
    }

    // Getting the "code" URL parameter
    String[] code = req.getParameterValues(CODE_URL_PARAM_NAME);

    // Checking conditions on the "code" URL parameter
    if (code == null || code.length == 0) {
      resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "The \"code\" URL parameter is missing");
      return;
    }
// สร้าง URL คำขอขาเข้า String requestUrl = getOAuthCodeCallbackHandlerUrl(req); // แลกเปลี่ยนรหัสเพื่อรับโทเค็น OAuth AccessTokenResponse accessTokenResponse = exchangeCodeForAccessAndRefreshTokens(code[0], requestUrl); // ดึงข้อมูลผู้ใช้ปัจจุบัน // การดำเนินการนี้ใช้บริการผู้ใช้ของ App Engine แต่คุณควรแทนที่การดำเนินการนี้ด้วยการดำเนินการของคุณเองสำหรับผู้ใช้/การเข้าสู่ระบบ UserService userService = UserServiceFactory.getUserService(); String email = userService.getCurrentUser().getEmail(); // บันทึกโทเค็น oauthTokenDao.saveKeys(accessTokenResponse, email); resp.sendRedirect(REDIRECT_URL); }
  /**
   * Construct the OAuth code callback handler URL.
   *
   * @param req the HttpRequest object
   * @return The constructed request's URL
   */
  public static String getOAuthCodeCallbackHandlerUrl(HttpServletRequest req) {
    String scheme = req.getScheme() + "://";
    String serverName = req.getServerName();
    String serverPort = (req.getServerPort() == 80) ? "" : ":" + req.getServerPort();
    String contextPath = req.getContextPath();
    String servletPath = URL_MAPPING;
    String pathInfo = (req.getPathInfo() == null) ? "" : req.getPathInfo();
    return scheme + serverName + serverPort + contextPath + servletPath + pathInfo;
  }
/** * แลกเปลี่ยนรหัสที่ระบุเพื่อรับโทเค็นการแลกเปลี่ยนและโทเค็นสำหรับรีเฟรช * * @param code The code gotten back from the authorization service * @param currentUrl The URL of the callback * @param oauthProperties The object containing the OAuth configuration * @return The object containing both an access and refresh token * @throws IOException */ public AccessTokenResponse exchangeCodeForAccessAndRefreshTokens(String code, String currentUrl) throws IOException { HttpTransport httpTransport = new NetHttpTransport(); JacksonFactory jsonFactory = new JacksonFactory(); // Loading the oauth config file OAuthProperties oauthProperties = new OAuthProperties(); return new GoogleAuthorizationCodeGrant(httpTransport, jsonFactory, oauthProperties .getClientId(), oauthProperties.getClientSecret(), code, currentUrl).execute(); } }
ไฟล์ OAuthCodeCallbackHandlerServlet.java

หมายเหตุ: การใช้งานข้างต้นใช้ไลบรารี App Engine บางรายการ ซึ่งใช้เพื่อลดความซับซ้อน หากคุณกำลังพัฒนาแอปสำหรับแพลตฟอร์มอื่น คุณสามารถใช้อินเทอร์เฟซ UserService อีกครั้งซึ่งจัดการการตรวจสอบสิทธิ์ของผู้ใช้

อ่านงานของผู้ใช้และแสดงงาน

ผู้ใช้ให้สิทธิ์แอปพลิเคชันเข้าถึงงาน แอปพลิเคชันมีโทเค็นการรีเฟรชที่บันทึกไว้ในที่เก็บข้อมูลที่เข้าถึงได้ผ่าน OAuthTokenDao ตอนนี้เซิร์วิต PrintTaskListsTitlesServlet สามารถใช้โทเค็นเหล่านี้เพื่อเข้าถึงงานของผู้ใช้และแสดงงานเหล่านั้นได้แล้ว

โค้ดที่เพิ่มลงในไฟล์ด้านล่างจะไฮไลต์ไวยากรณ์ ส่วนโค้ดที่มีอยู่แล้วจะเป็นสีเทา

package com.google.oauthsample;

import ...

/**
 * Simple sample Servlet which will display the tasks in the default task list of the user.
 */
@SuppressWarnings("serial")
public class PrintTasksTitlesServlet extends HttpServlet {

  /**
   * The OAuth Token DAO implementation, used to persist the OAuth refresh token.
   * Consider injecting it instead of using a static initialization. Also we are
   * using a simple memory implementation as a mock. Change the implementation to
   * using your database system.
   */
  public static OAuthTokenDao oauthTokenDao = new OAuthTokenDaoMemoryImpl();

  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    // Getting the current user
    // This is using App Engine's User Service but you should replace this to
    // your own user/login implementation
    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();

    // If the user is not logged-in it is redirected to the login service, then back to this page
    if (user == null) {
      resp.sendRedirect(userService.createLoginURL(getFullRequestUrl(req)));
      return;
    }

    // Checking if we already have tokens for this user in store
    AccessTokenResponse accessTokenResponse = oauthTokenDao.getKeys(user.getEmail());

    // If we don't have tokens for this user
    if (accessTokenResponse == null) {
      OAuthProperties oauthProperties = new OAuthProperties();
      // Redirect to the Google OAuth 2.0 authorization endpoint
      resp.sendRedirect(new GoogleAuthorizationRequestUrl(oauthProperties.getClientId(),
          OAuthCodeCallbackHandlerServlet.getOAuthCodeCallbackHandlerUrl(req), oauthProperties
              .getScopesAsString()).build());
      return;
    }
// พิมพ์ชื่อรายการงานของผู้ใช้ในการตอบกลับ resp.setContentType("text/plain"); resp.getWriter().append("ชื่อรายการงานของผู้ใช้ " + user.getEmail() + "\n\n"); printTasksTitles(accessTokenResponse, resp.getWriter());
  }

  /**
   * Construct the request's URL without the parameter part.
   *
   * @param req the HttpRequest object
   * @return The constructed request's URL
   */
  public static String getFullRequestUrl(HttpServletRequest req) {
    String scheme = req.getScheme() + "://";
    String serverName = req.getServerName();
    String serverPort = (req.getServerPort() == 80) ? "" : ":" + req.getServerPort();
    String contextPath = req.getContextPath();
    String servletPath = req.getServletPath();
    String pathInfo = (req.getPathInfo() == null) ? "" : req.getPathInfo();
    String queryString = (req.getQueryString() == null) ? "" : "?" + req.getQueryString();
    return scheme + serverName + serverPort + contextPath + servletPath + pathInfo + queryString;
  }
/** * ใช้ Google Tasks API เพื่อดึงข้อมูลรายการงานของผู้ใช้ในรายการงานเริ่มต้น * * * @param accessTokenResponse ออบเจ็กต์ AccessTokenResponse ของ OAuth 2.0 ที่มีโทเค็นการเข้าถึงและโทเค็นการรีเฟรช * @param output ตัวเขียนสตรีมเอาต์พุตที่จะเขียนชื่อรายการงาน * @return รายการชื่องานของผู้ใช้ในรายการงานเริ่มต้น * @throws IOException */ public void printTasksTitles(AccessTokenResponse accessTokenResponse, Writer output) throws IOException { // Initializing the Tasks service HttpTransport transport = new NetHttpTransport(); JsonFactory jsonFactory = new JacksonFactory(); OAuthProperties oauthProperties = new OAuthProperties(); GoogleAccessProtectedResource accessProtectedResource = new GoogleAccessProtectedResource( accessTokenResponse.accessToken, transport, jsonFactory, oauthProperties.getClientId(), oauthProperties.getClientSecret(), accessTokenResponse.refreshToken); Tasks service = new Tasks(transport, accessProtectedResource, jsonFactory); // Using the initialized Tasks API service to query the list of tasks lists com.google.api.services.tasks.model.Tasks tasks = service.tasks.list("@default").execute(); for (Task task : tasks.items) { output.append(task.title + "\n"); } } }
ไฟล์ PrintTasksTitlesServlet.java

ผู้ใช้จะแสดงพร้อมกับงานต่อไปนี้

งานของผู้ใช้
งานของผู้ใช้

แอปพลิเคชันตัวอย่าง

ดาวน์โหลดโค้ดสําหรับแอปพลิเคชันตัวอย่างนี้ได้ที่นี่ โปรดดู