הרשאת בקשות

בקשות ל-Google Mirror API חייבות להיות מאושרות באמצעות פרטי כניסה של OAuth 2.0. כדאי להשתמש בתהליך בצד השרת כשהאפליקציה צריכה לגשת לממשקי Google API מטעם המשתמש, למשל כשהמשתמש במצב אופליין. בגישה הזו צריך להעביר קוד הרשאה חד-פעמי מהלקוח לשרת, שמשמש לקבלת טוקנים של גישה ורענון לשרת.

יצירת מזהה לקוח וסוד לקוח

קודם צריך להפעיל את Google Mirror API באפליקציה. אפשר לעשות את זה בפרויקט ה-API ב-Google APIs Console.

  1. יוצרים פרויקט API ב-Google APIs Console.
  2. בפרויקט API, בוחרים בכרטיסייה Services ומפעילים את Google Mirror API.
  3. בכרטיסייה API Access (גישה ל-API) בפרויקט ה-API, לוחצים על Create an OAuth 2.0 client ID (יצירת מזהה לקוח OAuth 2.0).
  4. בקטע פרטי מיתוג, מזינים שם לאפליקציה (למשל, 'שירות Glass שלי') ולוחצים על הבא. הוספת לוגו של מוצר היא אופציונלית.
  5. בקטע Client ID Settings (הגדרות מזהה לקוח), מבצעים את הפעולות הבאות:
    1. ב-Application type בוחרים באפשרות Web application.
    2. לוחצים על הקישור אפשרויות נוספות ליד הכותרת האתר או שם המארח שלך.
    3. מזינים את שם המארח בשדות Authorized Redirect URIs (כתובות URL מורשות להפניה אוטומטית) ו-JavaScript origins (מקורות JavaScript).
    4. לוחצים על Create Client ID (יצירת מזהה לקוח).
  6. בדף API Access, מאתרים את הקטע Client ID for Web applications ורושמים את הערכים של Client ID ושל Client Secret.

טיפול בבקשות הרשאה

כשמשתמש טוען את האפליקציה בפעם הראשונה, מוצג לו תיבת דו-שיח שבה הוא יכול להעניק לאפליקציה הרשאה לגשת לחשבון Google Glass שלו בהיקפי ההרשאות המבוקשים. אחרי ההרשאה הראשונית הזו, תיבת הדו-שיח של ההרשאות תוצג למשתמש רק אם ה-Client-ID של האפליקציה ישתנה או אם ההיקפים המבוקשים השתנו.

אימות המשתמש

אם הכניסה הראשונית מצליחה, היא מחזירה אובייקט של תוצאת הרשאה שמכיל קוד הרשאה.

המרת קוד ההרשאה לטוקן גישה

קוד ההרשאה הוא קוד חד-פעמי שהשרת יכול להחליף באסימון גישה. אסימון הגישה הזה מועבר אל Google Mirror API כדי להעניק לאפליקציה שלכם גישה לנתוני המשתמשים למשך זמן מוגבל.

אם האפליקציה שלכם דורשת גישה אל offline, בפעם הראשונה שהאפליקציה מחליפה את קוד ההרשאה, היא מקבלת גם אסימון רענון שמשמש אותה לקבלת אסימון גישה חדש אחרי שפג התוקף של האסימון הקודם. האפליקציה שלכם מאחסנת את טוקן הרענון הזה (בדרך כלל במסד נתונים בשרת) לשימוש מאוחר יותר.

בדוגמאות הקוד הבאות מוצג איך להחליף קוד הרשאה בטוקן גישה עם הרשאת גישה offline ולאחסן את טוקן הרענון.

Java

מחליפים את הערך CLIENTSECRETS_LOCATION במיקום של קובץ client_secrets.json.

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeRequestUrl;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.oauth2.Oauth2;
import com.google.api.services.oauth2.model.Userinfo;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

// ...

class MyClass {

  // Path to client_secrets.json which should contain a JSON document such as:
  //   {
  //     "web": {
  //       "client_id": "[[YOUR_CLIENT_ID]]",
  //       "client_secret": "[[YOUR_CLIENT_SECRET]]",
  //       "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  //       "token_uri": "https://accounts.google.com/o/oauth2/token"
  //     }
  //   }
  private static final String CLIENTSECRETS_LOCATION = "client_secrets.json";

  private static final String REDIRECT_URI = "<YOUR_REGISTERED_REDIRECT_URI>";
  private static final List<String> SCOPES = Arrays.asList(
      "https://www.googleapis.com/auth/glass.timeline",
      "https://www.googleapis.com/auth/userinfo.profile");

  private static GoogleAuthorizationCodeFlow flow = null;

  /**
   * Exception thrown when an error occurred while retrieving credentials.
   */
  public static class GetCredentialsException extends Exception {

    protected String authorizationUrl;

    /**
     * Construct a GetCredentialsException.
     *
     * @param authorizationUrl The authorization URL to redirect the user to.
     */
    public GetCredentialsException(String authorizationUrl) {
      this.authorizationUrl = authorizationUrl;
    }

    /**
     * Set the authorization URL.
     */
    public void setAuthorizationUrl(String authorizationUrl) {
      this.authorizationUrl = authorizationUrl;
    }

    /**
     * @return the authorizationUrl
     */
    public String getAuthorizationUrl() {
      return authorizationUrl;
    }
  }

  /**
   * Exception thrown when a code exchange has failed.
   */
  public static class CodeExchangeException extends GetCredentialsException {

    /**
     * Construct a CodeExchangeException.
     *
     * @param authorizationUrl The authorization URL to redirect the user to.
     */
    public CodeExchangeException(String authorizationUrl) {
      super(authorizationUrl);
    }

  }

  /**
   * Exception thrown when no refresh token has been found.
   */
  public static class NoRefreshTokenException extends GetCredentialsException {

    /**
     * Construct a NoRefreshTokenException.
     *
     * @param authorizationUrl The authorization URL to redirect the user to.
     */
    public NoRefreshTokenException(String authorizationUrl) {
      super(authorizationUrl);
    }

  }

  /**
   * Exception thrown when no user ID could be retrieved.
   */
  private static class NoUserIdException extends Exception {
  }

  /**
   * Retrieved stored credentials for the provided user ID.
   *
   * @param userId User's ID.
   * @return Stored Credential if found, {@code null} otherwise.
   */
  static Credential getStoredCredentials(String userId) {
    // TODO: Implement this method to work with your database. Instantiate a new
    // Credential instance with stored accessToken and refreshToken.
    throw new UnsupportedOperationException();
  }

  /**
   * Store OAuth 2.0 credentials in the application's database.
   *
   * @param userId User's ID.
   * @param credentials The OAuth 2.0 credentials to store.
   */
  static void storeCredentials(String userId, Credential credentials) {
    // TODO: Implement this method to work with your database.
    // Store the credentials.getAccessToken() and credentials.getRefreshToken()
    // string values in your database.
    throw new UnsupportedOperationException();
  }

  /**
   * Build an authorization flow and store it as a static class attribute.
   *
   * @return GoogleAuthorizationCodeFlow instance.
   * @throws IOException Unable to load client_secrets.json.
   */
  static GoogleAuthorizationCodeFlow getFlow() throws IOException {
    if (flow == null) {
      HttpTransport httpTransport = new NetHttpTransport();
      JacksonFactory jsonFactory = new JacksonFactory();
      GoogleClientSecrets clientSecrets =
          GoogleClientSecrets.load(jsonFactory,
              MyClass.class.getResourceAsStream(CLIENTSECRETS_LOCATION));
      flow =
          new GoogleAuthorizationCodeFlow.Builder(httpTransport, jsonFactory, clientSecrets, SCOPES)
              .setAccessType("offline").setApprovalPrompt("force").build();
    }
    return flow;
  }

  /**
   * Exchange an authorization code for OAuth 2.0 credentials.
   *
   * @param authorizationCode Authorization code to exchange for OAuth 2.0
   *        credentials.
   * @return OAuth 2.0 credentials.
   * @throws CodeExchangeException An error occurred.
   */
  static Credential exchangeCode(String authorizationCode)
      throws CodeExchangeException {
    try {
      GoogleAuthorizationCodeFlow flow = getFlow();
      GoogleTokenResponse response =
          flow.newTokenRequest(authorizationCode).setRedirectUri(REDIRECT_URI).execute();
      return flow.createAndStoreCredential(response, null);
    } catch (IOException e) {
      System.err.println("An error occurred: " + e);
      throw new CodeExchangeException(null);
    }
  }

  /**
   * Send a request to the UserInfo API to retrieve the user's information.
   *
   * @param credentials OAuth 2.0 credentials to authorize the request.
   * @return User's information.
   * @throws NoUserIdException An error occurred.
   */
  static Userinfo getUserInfo(Credential credentials)
      throws NoUserIdException {
    Oauth2 userInfoService =
        new Oauth2.Builder(new NetHttpTransport(), new JacksonFactory(), credentials).build();
    Userinfo userInfo = null;
    try {
      userInfo = userInfoService.userinfo().get().execute();
    } catch (IOException e) {
      System.err.println("An error occurred: " + e);
    }
    if (userInfo != null && userInfo.getId() != null) {
      return userInfo;
    } else {
      throw new NoUserIdException();
    }
  }

  /**
   * Retrieve the authorization URL.
   *
   * @param userId User's Google ID.
   * @param state State for the authorization URL.
   * @return Authorization URL to redirect the user to.
   * @throws IOException Unable to load client_secrets.json.
   */
  public static String getAuthorizationUrl(String userId, String state) throws IOException {
    GoogleAuthorizationCodeRequestUrl urlBuilder =
        getFlow().newAuthorizationUrl().setRedirectUri(REDIRECT_URI).setState(state);
    urlBuilder.set("user_id", userId);
    return urlBuilder.build();
  }

  /**
   * Retrieve credentials using the provided authorization code.
   *
   * This function exchanges the authorization code for an access token and
   * queries the UserInfo API to retrieve the user's Google ID. If a
   * refresh token has been retrieved along with an access token, it is stored
   * in the application database using the user's Google ID as key. If no
   * refresh token has been retrieved, the function checks in the application
   * database for one and returns it if found or throws a NoRefreshTokenException
   * with the authorization URL to redirect the user to.
   *
   * @param authorizationCode Authorization code to use to retrieve an access
   *        token.
   * @param state State to set to the authorization URL in case of error.
   * @return OAuth 2.0 credentials instance containing an access and refresh
   *         token.
   * @throws NoRefreshTokenException No refresh token could be retrieved from
   *         the available sources.
   * @throws IOException Unable to load client_secrets.json.
   */
  public static Credential getCredentials(String authorizationCode, String state)
      throws CodeExchangeException, NoRefreshTokenException, IOException {
    String userId = "";
    try {
      Credential credentials = exchangeCode(authorizationCode);
      Userinfo userInfo = getUserInfo(credentials);
      userId = userInfo.getId();
      if (credentials.getRefreshToken() != null) {
        storeCredentials(userId, credentials);
        return credentials;
      } else {
        credentials = getStoredCredentials(userId);
        if (credentials != null && credentials.getRefreshToken() != null) {
          return credentials;
        }
      }
    } catch (CodeExchangeException e) {
      e.printStackTrace();
      // Glass services should try to retrieve the user and credentials for the current
      // session.
      // If none is available, redirect the user to the authorization URL.
      e.setAuthorizationUrl(getAuthorizationUrl(userId, state));
      throw e;
    } catch (NoUserIdException e) {
      e.printStackTrace();
    }
    // No refresh token has been retrieved.
    String authorizationUrl = getAuthorizationUrl(userId, state);
    throw new NoRefreshTokenException(authorizationUrl);
  }

}

Python

מחליפים את הערך CLIENTSECRETS_LOCATION במיקום של קובץ client_secrets.json.

import logging
from oauth2client.client import flow_from_clientsecrets
from oauth2client.client import FlowExchangeError
from apiclient.discovery import build
# ...


# Path to client_secrets.json which should contain a JSON document such as:
#   {
#     "web": {
#       "client_id": "[[YOUR_CLIENT_ID]]",
#       "client_secret": "[[YOUR_CLIENT_SECRET]]",
#       "redirect_uris": [],
#       "auth_uri": "https://accounts.google.com/o/oauth2/auth",
#       "token_uri": "https://accounts.google.com/o/oauth2/token"
#     }
#   }
CLIENTSECRETS_LOCATION = '<PATH/TO/CLIENT_SECRETS.JSON>'
REDIRECT_URI = '<YOUR_REGISTERED_REDIRECT_URI>'
SCOPES = [
    'https://www.googleapis.com/auth/glass.timeline',
    'https://www.googleapis.com/auth/userinfo.profile',
    # Add other requested scopes.
]

class GetCredentialsException(Exception):
  """Error raised when an error occurred while retrieving credentials.

  Attributes:
    authorization_url: Authorization URL to redirect the user to in order to
                       request offline access.
  """

  def __init__(self, authorization_url):
    """Construct a GetCredentialsException."""
    self.authorization_url = authorization_url


class CodeExchangeException(GetCredentialsException):
  """Error raised when a code exchange has failed."""


class NoRefreshTokenException(GetCredentialsException):
  """Error raised when no refresh token has been found."""


class NoUserIdException(Exception):
  """Error raised when no user ID could be retrieved."""


def get_stored_credentials(user_id):
  """Retrieved stored credentials for the provided user ID.

  Args:
    user_id: User's ID.
  Returns:
    Stored oauth2client.client.OAuth2Credentials if found, None otherwise.
  Raises:
    NotImplemented: This function has not been implemented.
  """
  # TODO: Implement this function to work with your database.
  #       To instantiate an OAuth2Credentials instance from a Json
  #       representation, use the oauth2client.client.Credentials.new_from_json
  #       class method.
  raise NotImplementedError()


def store_credentials(user_id, credentials):
  """Store OAuth 2.0 credentials in the application's database.

  This function stores the provided OAuth 2.0 credentials using the user ID as
  key.

  Args:
    user_id: User's ID.
    credentials: OAuth 2.0 credentials to store.
  Raises:
    NotImplemented: This function has not been implemented.
  """
  # TODO: Implement this function to work with your database.
  #       To retrieve a Json representation of the credentials instance, call the
  #       credentials.to_json() method.
  raise NotImplementedError()


def exchange_code(authorization_code):
  """Exchange an authorization code for OAuth 2.0 credentials.

  Args:
    authorization_code: Authorization code to exchange for OAuth 2.0
                        credentials.
  Returns:
    oauth2client.client.OAuth2Credentials instance.
  Raises:
    CodeExchangeException: an error occurred.
  """
  flow = flow_from_clientsecrets(CLIENTSECRETS_LOCATION, ' '.join(SCOPES))
  flow.redirect_uri = REDIRECT_URI
  try:
    credentials = flow.step2_exchange(authorization_code)
    return credentials
  except FlowExchangeError, error:
    logging.error('An error occurred: %s', error)
    raise CodeExchangeException(None)


def get_user_info(credentials):
  """Send a request to the UserInfo API to retrieve the user's information.

  Args:
    credentials: oauth2client.client.OAuth2Credentials instance to authorize the
                 request.
  Returns:
    User information as a dict.
  """
  user_info_service = build(
      serviceName='oauth2', version='v2',
      http=credentials.authorize(httplib2.Http()))
  user_info = None
  try:
    user_info = user_info_service.userinfo().get().execute()
  except errors.HttpError, e:
    logging.error('An error occurred: %s', e)
  if user_info and user_info.get('id'):
    return user_info
  else:
    raise NoUserIdException()


def get_authorization_url(user_id, state):
  """Retrieve the authorization URL.

  Args:
    user_id: User's Google ID.
    state: State for the authorization URL.
  Returns:
    Authorization URL to redirect the user to.
  """
  flow = flow_from_clientsecrets(CLIENTSECRETS_LOCATION, ' '.join(SCOPES))
  flow.params['access_type'] = 'offline'
  flow.params['approval_prompt'] = 'force'
  flow.params['user_id'] = user_id
  flow.params['state'] = state
  return flow.step1_get_authorize_url(REDIRECT_URI)


def get_credentials(authorization_code, state):
  """Retrieve credentials using the provided authorization code.

  This function exchanges the authorization code for an access token and queries
  the UserInfo API to retrieve the user's Google ID.
  If a refresh token has been retrieved along with an access token, it is stored
  in the application database using the user's Google ID as key.
  If no refresh token has been retrieved, the function checks in the application
  database for one and returns it if found or raises a NoRefreshTokenException
  with the authorization URL to redirect the user to.

  Args:
    authorization_code: Authorization code to use to retrieve an access token.
    state: State to set to the authorization URL in case of error.
  Returns:
    oauth2client.client.OAuth2Credentials instance containing an access and
    refresh token.
  Raises:
    CodeExchangeError: Could not exchange the authorization code.
    NoRefreshTokenException: No refresh token could be retrieved from the
                             available sources.
  """
  user_id = ''
  try:
    credentials = exchange_code(authorization_code)
    user_info = get_user_info(credentials)
    user_id = user_info.get('id')
    if credentials.refresh_token is not None:
      store_credentials(user_id, credentials)
      return credentials
    else:
      credentials = get_stored_credentials(user_id)
      if credentials and credentials.refresh_token is not None:
        return credentials
  except CodeExchangeException, error:
    logging.error('An error occurred during code exchange.')
    # Glass services should try to retrieve the user and credentials for the current
    # session.
    # If none is available, redirect the user to the authorization URL.
    error.authorization_url = get_authorization_url(user_id, state)
    raise error
  except NoUserIdException:
    logging.error('No user ID could be retrieved.')
  # No refresh token has been retrieved.
  authorization_url = get_authorization_url(user_id, state)
  raise NoRefreshTokenException(authorization_url)

PHP

הפונקציה getCredentials מאחזרת פרטי כניסה מסוג OAuth 2.0 החל מקוד ההרשאה שצוין. אם לא ניתן לאחזר טוקן רענון, נוצר חריג עם כתובת URL של הרשאה להפניה אוטומטית של המשתמש כדי לבקש גישה אופליין.

<?php
require_once 'google-api-php-client/src/Google_Client.php';
require_once "google-api-php-client/src/contrib/Google_Oauth2Service.php";
session_start();
// ...

$CLIENT_ID = '<YOUR_CLIENT_ID>';
$CLIENT_SECRET = '<YOUR_CLIENT_SECRET>';
$REDIRECT_URI = '<YOUR_REGISTERED_REDIRECT_URI>';
$SCOPES = array(
    'https://www.googleapis.com/auth/glass.timeline',
    'https://www.googleapis.com/auth/userinfo.profile');


/**
 * Exception thrown when an error occurred while retrieving credentials.
 */
class GetCredentialsException extends Exception {
  protected $authorizationUrl;

  /**
   * Construct a GetCredentialsException.
   *
   * @param authorizationUrl The authorization URL to redirect the user to.
   */
  public function __construct($authorizationUrl) {
    $this->authorizationUrl = $authorizationUrl;
  }

  /**
   * @return the authorizationUrl.
   */
  public function getAuthorizationUrl() {
    return $this->authorizationUrl;
  }

  /**
   * Set the authorization URL.
   */
  public function setAuthorizationurl($authorizationUrl) {
    $this->authorizationUrl = $authorizationUrl;
  }
}

/**
 * Exception thrown when no refresh token has been found.
 */
class NoRefreshTokenException extends GetCredentialsException {}

/**
 * Exception thrown when a code exchange has failed.
 */
class CodeExchangeException extends GetCredentialsException {}

/**
 * Exception thrown when no user ID could be retrieved.
 */
class NoUserIdException extends Exception {}

/**
 * Retrieved stored credentials for the provided user ID.
 *
 * @param String $userId User's ID.
 * @return String Json representation of the OAuth 2.0 credentials.
 */
function getStoredCredentials($userId) {
  // TODO: Implement this function to work with your database.
  throw new RuntimeException('Not implemented!');
}

/**
 * Store OAuth 2.0 credentials in the application's database.
 *
 * @param String $userId User's ID.
 * @param String $credentials Json representation of the OAuth 2.0 credentials to
                              store.
 */
function storeCredentials($userId, $credentials) {
  // TODO: Implement this function to work with your database.
  throw new RuntimeException('Not implemented!');
}

/**
 * Exchange an authorization code for OAuth 2.0 credentials.
 *
 * @param String $authorizationCode Authorization code to exchange for OAuth 2.0
 *                                  credentials.
 * @return String Json representation of the OAuth 2.0 credentials.
 * @throws CodeExchangeException An error occurred.
 */
function exchangeCode($authorizationCode) {
  try {
    global $CLIENT_ID, $CLIENT_SECRET, $REDIRECT_URI;
    $client = new Google_Client();

    $client->setClientId($CLIENT_ID);
    $client->setClientSecret($CLIENT_SECRET);
    $client->setRedirectUri($REDIRECT_URI);
    $_GET['code'] = $authorizationCode;
    return $client->authenticate();
  } catch (Google_AuthException $e) {
    print 'An error occurred: ' . $e->getMessage();
    throw new CodeExchangeException(null);
  }
}

/**
 * Send a request to the UserInfo API to retrieve the user's information.
 *
 * @param String credentials OAuth 2.0 credentials to authorize the request.
 * @return Userinfo User's information.
 * @throws NoUserIdException An error occurred.
 */
function getUserInfo($credentials) {
  $apiClient = new Google_Client();
  $apiClient->setUseObjects(true);
  $apiClient->setAccessToken($credentials);
  $userInfoService = new Google_Oauth2Service($apiClient);
  $userInfo = null;
  try {
    $userInfo = $userInfoService->userinfo->get();
  } catch (Google_Exception $e) {
    print 'An error occurred: ' . $e->getMessage();
  }
  if ($userInfo != null && $userInfo->getId() != null) {
    return $userInfo;
  } else {
    throw new NoUserIdException();
  }
}

/**
 * Retrieve the authorization URL.
 *
 * @param String $userId User's Google ID.
 * @param String $state State for the authorization URL.
 * @return String Authorization URL to redirect the user to.
 */
function getAuthorizationUrl($userId, $state) {
  global $CLIENT_ID, $REDIRECT_URI, $SCOPES;
  $client = new Google_Client();

  $client->setClientId($CLIENT_ID);
  $client->setRedirectUri($REDIRECT_URI);
  $client->setAccessType('offline');
  $client->setApprovalPrompt('force');
  $client->setState($state);
  $client->setScopes($SCOPES);
  $tmpUrl = parse_url($client->createAuthUrl());
  $query = explode('&', $tmpUrl['query']);
  $query[] = 'user_id=' . urlencode($userId);
  return
      $tmpUrl['scheme'] . '://' . $tmpUrl['host'] . $tmpUrl['port'] .
      $tmpUrl['path'] . '?' . implode('&', $query);
}

/**
 * Retrieve credentials using the provided authorization code.
 *
 * This function exchanges the authorization code for an access token and
 * queries the UserInfo API to retrieve the user's Google ID. If a
 * refresh token has been retrieved along with an access token, it is stored
 * in the application database using the user's Google ID as key. If no
 * refresh token has been retrieved, the function checks in the application
 * database for one and returns it if found or throws a NoRefreshTokenException
 * with the authorization URL to redirect the user to.
 *
 * @param String authorizationCode Authorization code to use to retrieve an access
 *                                 token.
 * @param String state State to set to the authorization URL in case of error.
 * @return String Json representation of the OAuth 2.0 credentials.
 * @throws NoRefreshTokenException No refresh token could be retrieved from
 *         the available sources.
 */
function getCredentials($authorizationCode, $state) {
  $userId = '';
  try {
    $credentials = exchangeCode($authorizationCode);
    $userInfo = getUserInfo($credentials);
    $userId = $userInfo->getId();
    $credentialsArray = json_decode($credentials, true);
    if (isset($credentialsArray['refresh_token'])) {
      storeCredentials($userId, $credentials);
      return $credentials;
    } else {
      $credentials = getStoredCredentials($userId);
      $credentialsArray = json_decode($credentials, true);
      if ($credentials != null &&
          isset($credentialsArray['refresh_token'])) {
        return $credentials;
      }
    }
  } catch (CodeExchangeException $e) {
    print 'An error occurred during code exchange.';
    // Glass services should try to retrieve the user and credentials for the current
    // session.
    // If none is available, redirect the user to the authorization URL.
    $e->setAuthorizationUrl(getAuthorizationUrl($userId, $state));
    throw $e;
  } catch (NoUserIdException $e) {
    print 'No user ID could be retrieved.';
  }
  // No refresh token has been retrieved.
  $authorizationUrl = getAuthorizationUrl($userId, $state);
  throw new NoRefreshTokenException($authorizationUrl);
}
?>

‎.NET

הפונקציה GetCredentials מאחזרת פרטי כניסה מסוג OAuth 2.0 החל מקוד ההרשאה שצוין. אם לא ניתן לאחזר טוקן רענון, נוצר חריג עם כתובת URL של הרשאה להפניה אוטומטית של המשתמש כדי לבקש גישה אופליין.

using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2;
using Google;
using Google.Apis.Authentication;
using Google.Apis.Authentication.OAuth2;
using Google.Apis.Authentication.OAuth2.DotNetOpenAuth;
using Google.Apis.Oauth2.v2;
using Google.Apis.Oauth2.v2.Data;
using Google.Apis.Services;
using System;
using System.Collections.Specialized;
using System.Web;
// ...

class MyClass {

  static String CLIENT_ID = "<YOUR_CLIENT_ID>";
  static String CLIENT_SECRET = "<YOUR_CLIENT_SECRET>";
  static String REDIRECT_URI = "<YOUR_REGISTERED_REDIRECT_URI>";
  static String[] SCOPES = new String[] {
      "https://www.googleapis.com/auth/glass.timeline",
      "https://www.googleapis.com/auth/userinfo.profile"
  };

  /// <summary>
  /// Exception thrown when an error occurred while retrieving credentials.
  /// </summary>
  public class GetCredentialsException : Exception {

    public String AuthorizationUrl { get; set; }

    /// <summary>
    /// Construct a GetCredentialsException.
    /// </summary>
    /// @param authorizationUrl The authorization URL to redirect the user to.
    public GetCredentialsException(String authorizationUrl) {
      this.AuthorizationUrl = authorizationUrl;
    }

  }

  /// <summary>
  /// Exception thrown when no refresh token has been found.
  /// </summary>
  public class NoRefreshTokenException : GetCredentialsException {

    /// <summary>
    /// Construct a NoRefreshTokenException.
    /// </summary>
    /// @param authorizationUrl The authorization URL to redirect the user to.
    public NoRefreshTokenException(String authorizationUrl) : base(authorizationUrl) {
    }

  }

  /// <summary>
  /// Exception thrown when a code exchange has failed.
  /// </summary>
  private class CodeExchangeException : GetCredentialsException {

    /// <summary>
    /// Construct a CodeExchangeException.
    /// </summary>
    /// @param authorizationUrl The authorization URL to redirect the user to.
    public CodeExchangeException(String authorizationUrl) : base(authorizationUrl) {
    }

  }

  /// <summary>
  /// Exception thrown when no user ID could be retrieved.
  /// </summary>
  private class NoUserIdException : Exception {
  }

  /// <summary>
  /// Extends the NativeApplicationClient class to allow setting of a custom IAuthorizationState.
  /// </summary>
  public class StoredStateClient : NativeApplicationClient {
    /// <summary>
    /// Initializes a new instance of the <see cref="StoredStateClient"/> class.
    /// </summary>
    /// <param name="authorizationServer">The token issuer.</param>
    /// <param name="clientIdentifier">The client identifier.</param>
    /// <param name="clientSecret">The client secret.</param>
    public StoredStateClient(AuthorizationServerDescription authorizationServer,
        String clientIdentifier,
        String clientSecret,
        IAuthorizationState state)
        : base(authorizationServer, clientIdentifier, clientSecret) {
      this.State = state;
    }

    public IAuthorizationState State { get; private set; }

    /// <summary>
    /// Returns the IAuthorizationState stored in the StoredStateClient instance.
    /// </summary>
    /// <param name="provider">OAuth2 client.</param>
    /// <returns>The stored authorization state.</returns>
    static public IAuthorizationState GetState(StoredStateClient provider) {
      return provider.State;
    }
  }

  /// <summary>
  /// Retrieve an IAuthenticator instance using the provided state.
  /// </summary>
  /// <param name="credentials">OAuth 2.0 credentials to use.</param>
  /// <returns>Authenticator using the provided OAuth 2.0 credentials</returns>
  public static IAuthenticator GetAuthenticatorFromState(IAuthorizationState credentials) {
    var provider = new StoredStateClient(GoogleAuthenticationServer.Description, CLIENT_ID, CLIENT_SECRET, credentials);
    var auth = new OAuth2Authenticator<StoredStateClient>(provider, StoredStateClient.GetState);
    auth.LoadAccessToken();
    return auth;
  }

  /// <summary>
  /// Retrieved stored credentials for the provided user ID.
  /// </summary>
  /// <param name="userId">User's ID.</param>
  /// <returns>Stored GoogleAccessProtectedResource if found, null otherwise.</returns>
  static IAuthorizationState GetStoredCredentials(String userId) {
    // TODO: Implement this method to work with your database.
    throw new NotImplementedException();
  }

  /// <summary>
  /// Store OAuth 2.0 credentials in the application's database.
  /// </summary>
  /// <param name="userId">User's ID.</param>
  /// <param name="credentials">The OAuth 2.0 credentials to store.</param>
  static void StoreCredentials(String userId, IAuthorizationState credentials) {
    // TODO: Implement this method to work with your database.
    throw new NotImplementedException();
  }

  /// <summary>
  /// Exchange an authorization code for OAuth 2.0 credentials.
  /// </summary>
  /// <param name="authorizationCode">Authorization code to exchange for OAuth 2.0 credentials.</param>
  /// <returns>OAuth 2.0 credentials.</returns>
  /// <exception cref="CodeExchangeException">An error occurred.</exception>
  static IAuthorizationState ExchangeCode(String authorizationCode) {
    var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description, CLIENT_ID, CLIENT_SECRET);
    IAuthorizationState state = new AuthorizationState();
    state.Callback = new Uri(REDIRECT_URI);
    try {
      state = provider.ProcessUserAuthorization(authorizationCode, state);
      return state;
    } catch (ProtocolException) {
      throw new CodeExchangeException(null);
    }
  }

  /// <summary>
  /// Send a request to the UserInfo API to retrieve the user's information.
  /// </summary>
  /// <param name="credentials">OAuth 2.0 credentials to authorize the request.</param>
  /// <returns>User's information.</returns>
  /// <exception cref="NoUserIdException">An error occurred.</exception>
  static Userinfo GetUserInfo(IAuthorizationState credentials) {
    Oauth2Service userInfoService = new Oauth2Service(new BaseClientService.Initializer()
    {
        Authenticator = GetAuthenticatorFromState(credentials)
    });
    Userinfo userInfo = null;
    try {
      userInfo = userInfoService.Userinfo.Get().Fetch();
    } catch (GoogleApiRequestException e) {
      Console.WriteLine("An error occurred: " + e.Message);
    }
    if (userInfo != null && !String.IsNullOrEmpty(userInfo.Id)) {
      return userInfo;
    } else {
      throw new NoUserIdException();
    }
  }

  /// <summary>
  /// Retrieve the authorization URL.
  /// </summary>
  /// <param name="userId">User's Google ID.</param>
  /// <param name="state">State for the authorization URL.</param>
  /// <returns>Authorization URL to redirect the user to.</returns>
  public static String GetAuthorizationUrl(String userId, String state) {
    var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description);
    provider.ClientIdentifier = CLIENT_ID;

    IAuthorizationState authorizationState = new AuthorizationState(SCOPES);
    authorizationState.Callback = new Uri(REDIRECT_URI);

    UriBuilder builder = new UriBuilder(provider.RequestUserAuthorization(authorizationState));
    NameValueCollection queryParameters = HttpUtility.ParseQueryString(builder.Query);

    queryParameters.Set("access_type", "offline");
    queryParameters.Set("approval_prompt", "force");
    queryParameters.Set("user_id", userId);
    queryParameters.Set("state", state);

    builder.Query = queryParameters.ToString();
    return builder.Uri.ToString();
  }

  /// <summary>
  /// Retrieve credentials using the provided authorization code.
  ///
  /// This function exchanges the authorization code for an access token and
  /// queries the UserInfo API to retrieve the user's Google ID. If a
  /// refresh token has been retrieved along with an access token, it is stored
  /// in the application database using the user's Google ID as key. If no
  /// refresh token has been retrieved, the function checks in the application
  /// database for one and returns it if found or throws a NoRefreshTokenException
  /// with the authorization URL to redirect the user to.
  /// </summary>
  /// <param name="authorizationCode">Authorization code to use to retrieve an access token.</param>
  /// <param name="state">State to set to the authorization URL in case of error.</param>
  /// <returns>OAuth 2.0 credentials instance containing an access and refresh token.</returns>
  /// <exception cref="CodeExchangeException">
  /// An error occurred while exchanging the authorization code.
  /// </exception>
  /// <exception cref="NoRefreshTokenException">
  /// No refresh token could be retrieved from the available sources.
  /// </exception>
  public static IAuthenticator GetCredentials(String authorizationCode, String state) {
    String userId = "";
    try {
      IAuthorizationState credentials = ExchangeCode(authorizationCode);
      Userinfo userInfo = GetUserInfo(credentials);
      userId = userInfo.Id;
      if (!String.IsNullOrEmpty(credentials.RefreshToken)) {
        StoreCredentials(userId, credentials);
        return GetAuthenticatorFromState(credentials);
      } else {
        credentials = GetStoredCredentials(userId);
        if (credentials != null && !String.IsNullOrEmpty(credentials.RefreshToken)) {
          return GetAuthenticatorFromState(credentials);
        }
      }
    } catch (CodeExchangeException e) {
      Console.WriteLine("An error occurred during code exchange.");
      // Glass services should try to retrieve the user and credentials for the current
      // session.
      // If none is available, redirect the user to the authorization URL.
      e.AuthorizationUrl = GetAuthorizationUrl(userId, state);
      throw e;
    } catch (NoUserIdException) {
      Console.WriteLine("No user ID could be retrieved.");
    }
    // No refresh token has been retrieved.
    String authorizationUrl = GetAuthorizationUrl(userId, state);
    throw new NoRefreshTokenException(authorizationUrl);
  }

}

Ruby

הפונקציה get_credentials מאחזרת פרטי כניסה מסוג OAuth 2.0 החל מקוד ההרשאה שצוין. אם לא ניתן לאחזר טוקן רענון, נוצר חריג עם כתובת URL של הרשאה להפניה אוטומטית של המשתמש כדי לבקש גישה אופליין.

require 'google/api_client'

CLIENT_ID = '<YOUR_CLIENT_ID>'
CLIENT_SECRET = '<YOUR_CLIENT_SECRET>'
REDIRECT_URI = '<YOUR_REGISTERED_REDIRECT_URI>'
SCOPES = [
    'https://www.googleapis.com/auth/glass.timeline',
    'https://www.googleapis.com/auth/userinfo.profile',
    # Add other requested scopes.
]

##
# Error raised when an error occurred while retrieving credentials.
class GetCredentialsError < StandardError
  ##
  # Initialize a NoRefreshTokenError instance.
  #
  # @param [String] authorize_url
  #   Authorization URL to redirect the user to in order to in order to request
  #   offline access.
  def initialize(authorization_url)
    @authorization_url = authorization_url
  end

  def authorization_url=(authorization_url)
    @authorization_url = authorization_url
  end

  def authorization_url
    return @authorization_url
  end
end

##
# Error raised when a code exchange has failed.
class CodeExchangeError < GetCredentialsError
end

##
# Error raised when no refresh token has been found.
class NoRefreshTokenError < GetCredentialsError
end

##
# Error raised when no user ID could be retrieved.
class NoUserIdError < StandardError
end

##
# Retrieved stored credentials for the provided user ID.
#
# @param [String] user_id
#   User's ID.
# @return [Signet::OAuth2::Client]
#  Stored OAuth 2.0 credentials if found, nil otherwise.
def get_stored_credentials(user_id)
  raise NotImplementedError, 'get_stored_credentials is not implemented.'
end

##
# Store OAuth 2.0 credentials in the application's database.
#
# @param [String] user_id
#   User's ID.
# @param [Signet::OAuth2::Client] credentials
#   OAuth 2.0 credentials to store.
def store_credentials(user_id, credentials)
  raise NotImplementedError, 'store_credentials is not implemented.'
end

##
# Exchange an authorization code for OAuth 2.0 credentials.
#
# @param [String] auth_code
#   Authorization code to exchange for OAuth 2.0 credentials.
# @return [Signet::OAuth2::Client]
#  OAuth 2.0 credentials.
def exchange_code(authorization_code)
  client = Google::APIClient.new
  client.authorization.client_id = CLIENT_ID
  client.authorization.client_secret = CLIENT_SECRET
  client.authorization.code = authorization_code
  client.authorization.redirect_uri = REDIRECT_URI

  begin
    client.authorization.fetch_access_token!
    return client.authorization
  rescue Signet::AuthorizationError
    raise CodeExchangeError.new(nil)
  end
end

##
# Send a request to the UserInfo API to retrieve the user's information.
#
# @param [Signet::OAuth2::Client] credentials
#   OAuth 2.0 credentials to authorize the request.
# @return [Google::APIClient::Schema::Oauth2::V2::Userinfo]
#   User's information.
def get_user_info(credentials)
  client = Google::APIClient.new
  client.authorization = credentials
  oauth2 = client.discovered_api('oauth2', 'v2')
  result = client.execute!(:api_method => oauth2.userinfo.get)
  user_info = nil
  if result.status == 200
    user_info = result.data
  else
    puts "An error occurred: #{result.data['error']['message']}"
  end
  if user_info != nil && user_info.id != nil
    return user_info
  end
  raise NoUserIdError, "Unable to retrieve the user's Google ID."
end

##
# Retrieve authorization URL.
#
# @param [String] user_id
#   User's Google ID.
# @param [String] state
#   State for the authorization URL.
# @return [String]
#  Authorization URL to redirect the user to.
def get_authorization_url(user_id, state)
  client = Google::APIClient.new
  client.authorization.client_id = CLIENT_ID
  client.authorization.redirect_uri = REDIRECT_URI
  client.authorization.scope = SCOPES

  return client.authorization.authorization_uri(
    :options => {
       :approval_prompt => :force,
       :access_type => :offline,
       :user_id => user_id,
       :state => state
    }).to_s
end

##
# Retrieve credentials using the provided authorization code.
#
#  This function exchanges the authorization code for an access token and queries
#  the UserInfo API to retrieve the user's Google ID.
#  If a refresh token has been retrieved along with an access token, it is stored
#  in the application database using the user's Google ID as key.
#  If no refresh token has been retrieved, the function checks in the application
#  database for one and returns it if found or raises a NoRefreshTokenError
#  with an authorization URL to redirect the user to.
#
# @param [String] auth_code
#   Authorization code to use to retrieve an access token.
# @param [String] state
#   State to set to the authorization URL in case of error.
# @return [Signet::OAuth2::Client]
#  OAuth 2.0 credentials containing an access and refresh token.
def get_credentials(authorization_code, state)
  user_id = ''
  begin
    credentials = exchange_code(authorization_code)
    user_info = get_user_info(credentials)
    user_id = user_info.id
    if credentials.refresh_token != nil
      store_credentials(user_id, credentials)
      return credentials
    else
      credentials = get_stored_credentials(user_id)
      if credentials != nil && credentials.refresh_token != nil
        return credentials
      end
    end
  rescue CodeExchangeError => error
    print 'An error occurred during code exchange.'
    # Glass services should try to retrieve the user and credentials for the current
    # session.
    # If none is available, redirect the user to the authorization URL.
    error.authorization_url = get_authorization_url(user_id, state)
    raise error
  rescue NoUserIdError
    print 'No user ID could be retrieved.'
  end
  authorization_url = get_authorization_url(user_id, state)
  raise NoRefreshTokenError.new(authorization_url)
end

אימות באמצעות פרטי כניסה שמורים

כשהמשתמשים מבקרים באפליקציה שלכם אחרי תהליך הרשאה מוצלח בפעם הראשונה, האפליקציה יכולה להשתמש באסימון רענון מאוחסן כדי לאשר בקשות בלי להציג למשתמש הקצה בקשה לאישור.

אם כבר אימתתם את המשתמש, האפליקציה יכולה לאחזר את אסימון הרענון מהמסד שלה ולאחסן את האסימון בסשן בצד השרת. אם טוקן הרענון בוטל או שהוא לא תקף מסיבה אחרת, תצטרכו לזהות את זה ולנקוט פעולה מתאימה.

שימוש בפרטי כניסה מסוג OAuth 2.0

אחרי שמקבלים את פרטי הכניסה של OAuth 2.0 כמו שמוסבר בקטע הקודם, אפשר להשתמש בהם כדי לתת הרשאה לאובייקט שירות של Google Mirror API ולשלוח בקשות ל-API.

קטעי הקוד הבאים מראים איך ליצור מופע של אובייקט שירות של Google Mirror API ולתת לו הרשאה, ואיך לשלוח בקשה ל-Google Mirror API כדי לאחזר מטא-נתונים של timeline item.

יצירת מופע של אובייקט שירות

בדוגמת הקוד הזו אפשר לראות איך ליצור מופע של אובייקט שירות ואז לאשר לו לשלוח בקשות API.

Java

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;

import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson.JacksonFactory;

import com.google.api.services.mirror.Mirror;
// ...

public class MyClass {
  // ...

  /**
    * Build a Mirror service object.
    *
    * @param credentials OAuth 2.0 credentials.
    * @return Mirror service object.
    */
  static Mirror buildService(GoogleCredential credentials) {
    HttpTransport httpTransport = new NetHttpTransport();
    JacksonFactory jsonFactory = new JacksonFactory();

    return new Mirror.Builder(httpTransport, jsonFactory, credentials)
        .build();
  }

  // ...
}

Python

from apiclient.discovery import build
# ...

def build_service(credentials):
  """Build a Mirror service object.

  Args:
    credentials: OAuth 2.0 credentials.

  Returns:
    Mirror service object.
  """
  http = httplib2.Http()
  http = credentials.authorize(http)
  return build('mirror', 'v1', http=http)

PHP

<?php
session_start();

require_once "google-api-php-client/src/Google_Client.php";
require_once "google-api-php-client/src/contrib/Google_MirrorService.php";

// ...

/**
 * Build a Mirror service object.
 *
 * @param String credentials Json representation of the OAuth 2.0 credentials.
 * @return Google_MirrorService service object.
 */
function buildService($credentials) {
  $apiClient = new Google_Client();
  $apiClient->setUseObjects(true);
  $apiClient->setAccessToken($credentials);
  return new Google_MirrorService($apiClient);
}

// ...
?>

‎.NET

using Google.Apis.Authentication;

using Google.Apis.Mirror.v1;
using Google.Apis.Services;
// ...

public class MyClass {
  // ...

  /// <summary>
  /// Build a Mirror service object.
  /// </summary>
  /// <param name="credentials">OAuth 2.0 credentials.</param>
  /// <returns>Mirror service object.</returns>
  static MirrorService BuildService(IAuthenticator credentials) {
    return new MirrorService(new BaseClientService.Initializer()
    {
        Authenticator = credentials
    });
  }
}

Ruby

require 'google/api_client'

##
# Build a Mirror client instance.
#
# @param [Signet::OAuth2::Client] credentials
#   OAuth 2.0 credentials.
# @return [Google::APIClient]
#   Client instance
def build_client(credentials)
  client = Google::APIClient.new
  client.authorization = credentials
  client = client.discovered_api('mirror', 'v1')
  client
end

שליחת בקשות מורשות ובדיקה אם פרטי הכניסה בוטלו

קטע הקוד הבא משתמש במופע מורשה של שירות Google Mirror API ושולח בקשת GET מורשית ל-Google Mirror API כדי לאחזר מטא-נתונים של timeline item.

אם מתרחשת שגיאה, הקוד בודק קוד סטטוס HTTP 401, שצריך לטפל בו על ידי הפניית המשתמש לכתובת ה-URL של ההרשאה.

פעולות נוספות של Google Mirror API מתועדות במאמרי העזרה של ה-API.

Java

import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpResponseException;

import com.google.api.services.mirror.Mirror;
import com.google.api.services.mirror.model.TimelineItem;

import java.io.IOException;
// ...

public class MyClass {
  // ...

  /**
    * Print a timeline item's metadata.
    *
    * @param service Mirror service instance.
    * @param itemId ID of the timeline item to print metadata for.
    */
  static void printTimelineItem(Mirror service, String itemId) {
    try {
      TimelineItem item = service.timeline().get(itemId).execute();

      System.out.println("Text: " + item.getText());
      System.out.println("HTML: " + item.getHtml());
    } catch (HttpResponseException e) {
      if (e.getStatusCode() == 401) {
        // Credentials have been revoked.
        // TODO: Redirect the user to the authorization URL and/or
        //       remove the credentials from the database.
        throw new UnsupportedOperationException();
      }
    } catch (IOException e) {
      System.out.println("An error occurred: " + e);
    }
  }

  // ...
}

Python

from apiclient import errors
# ...

def print_timeline_item(service, item_id):
  """Print a timeline item's metadata.

  Args:
    service: Mirror service instance.
    item_id: ID of the timeline item to print metadata for.
  """
  try:
    item = service.timeline().get(id=item_id).execute()

    print 'Text: %s' % item['text']
    print 'HTML: %s' % item['html']
  except errors.HttpError, error:
    if error.resp.status == 401:
      # Credentials have been revoked.
      # TODO: Redirect the user to the authorization URL and/or remove
      #       the credentials from the database.
      raise NotImplementedError()

PHP

/**
 * Print a timeline item's metadata.
 *
 * @param Google_MirrorService $service Mirror service instance.
 * @param string $itemId ID of the timeline item to print metadata for.
 */
function printTimelineItem($service, $itemId) {
  try {
    $item = $service->timeline->get($itemId);

    print "Text: " . $item->getText() . "\n";
    print "HTML: " . $item->getHtml() . "\n";
  } catch (apiAuthException) {
    // Credentials have been revoked.
    // TODO: Redirect the user to the authorization URL and/or remove
    //       the credentials from the database.
    throw new RuntimeException('Not implemented!');
  } catch (apiException $e) {
    print "An error occurred: " . $e->getMessage();
  }
}

‎.NET

using Google;
using Google.Apis.Mirror.v1;
using Google.Apis.Mirror.v1.Data;

using System;
using System.Net;
// ...

public class MyClass {

  // ...

  /// <summary>
  /// Print a timeline item's metadata.
  /// </summary>
  /// <param name="service">Mirror service instance.</param>
  /// <param name="itemId">ID of the timeline item to print metadata for.</param>
  private static void printTimelineItem(MirrorService service, String itemId) {
    try {
      TimelineItem item = service.Timeline.Get(itemId).Fetch();

      Console.WriteLine("Text: " + item.Text);
      Console.WriteLine("HTML: " + item.Html);
    } catch (GoogleApiRequestException e) {
      if (e.HttpStatusCode == HttpStatusCode.Unauthorized) {
        // Credentials have been revoked.
        // TODO: Redirect the user to the authorization URL and/or remove the
        //       credentials from the database.
        throw new NotImplementedException();
      }
    }
  }

  //...

}

Ruby

require 'google/api_client'

##
# Print a timeline item's metadata.
#
# @param [Google::APIClient] client
#   Authorized client instance
# @param [String] item_id
#   ID of timeline item to print
# @return nil
def print_timeline_item(client, item_id)
  mirror = client.discovered_api('mirror', 'v1')
  result = client.execute(
    :api_method => mirror.timeline.get,
    :parameters => { 'id' => item_id })
  if result.success?
    item = result.data
    puts "Text: #{item.text}"
    puts "Html: #{item.html}"
  elseif result.status == 401
      # Credentials have been revoked.
      # TODO: Redirect the user to the authorization URL and/or remove
      #       the credentials from the database.
      raise NotImplementedError, 'Redirect the user.'
    end
  else
    puts "An error occurred: #{result.data['error']['message']}"
  end
end