Consumer SDK 可使用 JSON Web Token 提供授權,JSON Web Token (JWT) 是一種授權權杖,可為服務提供一或多項憑證附加資訊。
Consumer SDK 會使用應用程式提供的 JSON Web Token 與 Fleet Engine 通訊。如要進一步瞭解 Fleet Engine 伺服器預期的權杖,請參閱 JSON Web Token 和核發 JSON Web 權杖。
授權權杖提供下列 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 網路權杖。
授權權杖擷取工具範例
以下程式碼範例說明如何實作授權權杖回呼。
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
}
}
}