認証トークンを取得する

Consumer SDK は、JSON Web Token を使用した認可を提供します。JSON Web Token(JWT)は、サービスに関する 1 つ以上のクレームを提供する認可トークンです。

Consumer SDK は、アプリケーションから提供された JSON Web Token を使用して、Fleet Engine と通信します。Fleet Engine サーバーが想定するトークンの詳細については、JSON Web TokenJSON Web Token を発行するをご覧ください。

認可トークンを使用すると、次の Fleet Engine サービスにアクセスできます。

  • TripService - 車両の位置情報、ルート、予定時刻などのルートの詳細に Consumer SDK がアクセスできるようにします。ルートサービスの認証トークンには、トークンの authorization ヘッダーに tripid:TRIP_ID クレームを含める必要があります。ここで、TRIP_ID は共有されるオンデマンド ルートのルート ID です。

  • VehicleService - 車両密度レイヤの表示と集合ポイントの到着予定時間の推定に使用される、車両のおおよその位置に関する情報を Consumer SDK に提供します。Consumer SDK は近似位置情報のみを使用するため、車両サービスの認可トークンには vehicleid クレームは必要ありません。

トークンとは

信頼性の低い環境からの API メソッド呼び出しの場合、Fleet Engine では、適切なサービス アカウントによって署名された JSON Web Token(JWT)を使用する必要があります。信頼性の低い環境には、スマートフォンやブラウザが含まれます。JWT は、完全に信頼できる環境であるサーバー上で生成されます。JWT は署名され、暗号化され、有効期限が切れるか無効になるまで、その後のサーバーとのやり取りのためにクライアントに渡されます。

バックエンドは、標準のアプリケーションのデフォルト認証情報メカニズムを使用して、Fleet Engine に対して認証と承認を行う必要があります。適切なサービス アカウントで署名された JWT を使用してください。サービス アカウントのロールの一覧については、Fleet Engine の基本Fleet Engine サービス アカウントのロールをご覧ください。

一方、バックエンドは、標準のアプリケーションのデフォルト認証情報メカニズムを使用して、Fleet Engine に対して認証と承認を行う必要があります。

JSON Web Token の詳細については、Fleet Engine の基本JSON Web Token をご覧ください。

クライアントはどのようにトークンを取得しますか?

ドライバーまたはユーザーが適切な認可認証情報を使用してアプリにログインすると、そのデバイスから発行される更新では、適切な認可トークンを使用する必要があります。このトークンは、アプリの権限を Fleet Engine に通知します。

デベロッパーは、クライアントの実装で次の機能を提供する必要があります。

  • サーバーから JSON Web Token を取得します。
  • トークンを期限切れになるまで再利用し、トークンの更新を最小限に抑えます。
  • トークンの有効期限が切れたら更新します。

AuthTokenFactory クラスは、位置情報の更新時に認可トークンを生成します。SDK は、Fleet Engine に送信する更新情報とともにトークンをパッケージ化する必要があります。SDK を初期化する前に、サーバーサイドの実装でトークンを発行できることを確認します。

Fleet Engine サービスで想定されるトークンの詳細については、Fleet Engine のJSON Web Token の発行をご覧ください。

認可トークン取得ツールの例

次のコード例は、認証トークン コールバックを実装する方法を示しています。

Java

class JsonAuthTokenFactory implements AuthTokenFactory {

  private static final String TOKEN_URL =
      "https://yourauthserver.example/token";

  private static class CachedToken {
    String tokenValue;
    long expiryTimeMs;
    String tripId;
  }

  private CachedToken token;

  /*

*   This method is called on a background thread. Blocking is OK. However, be
*   aware that no information can be obtained from Fleet Engine until this
*   method returns.
*/
@Override
public String getToken(AuthTokenContext context) {
  // If there is no existing token or token has expired, go get a new one.
  String tripId = context.getTripId();
  if (tripId == null) {
    throw new RuntimeException("Trip ID is missing from AuthTokenContext");
  }
  if (token == null || System.currentTimeMillis() > token.expiryTimeMs ||
      !tripId.equals(token.tripId)) {
    token = fetchNewToken(tripId);
  }
  return token.tokenValue;
}

  private static CachedToken fetchNewToken(String tripId) {
    String url = TOKEN_URL + "/" + tripId;
    CachedToken token = new CachedToken();

    try (Reader r = new InputStreamReader(new URL(url).openStream())) {
      com.google.gson.JsonObject obj
          = com.google.gson.JsonParser.parseReader(r).getAsJsonObject();

      token.tokenValue = obj.get("ServiceToken").getAsString();
      token.expiryTimeMs = obj.get("TokenExpiryMs").getAsLong();

      /*

    *   The expiry time could be an hour from now, but just to try and avoid
    *   passing expired tokens, we subtract 5 minutes from that time.
    */
    token.expiryTimeMs -= 5 * 60 * 1000;
  } catch (IOException e) {
    /*
    *   It's OK to throw exceptions here. The error listeners will receive the
    *   error thrown here.
    */
    throw new RuntimeException("Could not get auth token", e);
  }
  token.tripId = tripId;

    return token;
  }
}

Kotlin

class JsonAuthTokenFactory : AuthTokenFactory() {

  private var token: CachedToken? = null

  /*

*   This method is called on a background thread. Blocking is OK. However, be
*   aware that no information can be obtained from Fleet Engine until this
*   method returns.
*/
override fun getToken(context: AuthTokenContext): String {
  // If there is no existing token or token has expired, go get a new one.
  val tripId =
    context.getTripId() ?:
      throw RuntimeException("Trip ID is missing from AuthTokenContext")

    if (token == null || System.currentTimeMillis() > token.expiryTimeMs ||
        tripId != token.tripId) {
      token = fetchNewToken(tripId)
    }

    return token.tokenValue
  }

  class CachedToken(
    var tokenValue: String? = "",
    var expiryTimeMs: Long = 0,
    var tripId: String? = "",
  )

  private companion object {
    const val TOKEN_URL = "https://yourauthserver.example/token"

    fun fetchNewToken(tripId: String) {
      val url = "$TOKEN_URL/$tripId"
      val token = CachedToken()

      try {
        val reader = InputStreamReader(URL(url).openStream())

        reader.use {
          val obj = com.google.gson.JsonParser.parseReader(r).getAsJsonObject()

          token.tokenValue = obj.get("ServiceToken").getAsString()
          token.expiryTimeMs = obj.get("TokenExpiryMs").getAsLong()

          /*

        *   The expiry time could be an hour from now, but just to try and avoid
        *   passing expired tokens, we subtract 5 minutes from that time.
        */
        token.expiryTimeMs -= 5 * 60 * 1000
      }
    } catch (e: IOException) {
      /*
            *   It's OK to throw exceptions here. The error listeners will receive the
            *   error thrown here.
      */
      throw RuntimeException("Could not get auth token", e)
    }

      token.tripId = tripId

      return token
    }
  }
}

次のステップ

Consumer SDK を初期化する