消费者 SDK 使用 JSON Web 令牌提供授权。JSON Web 令牌 (JWT) 是一种授权令牌,可提供一个或多个服务声明。
使用户 SDK 使用应用提供的 JSON Web 令牌与车队引擎进行通信。如需详细了解车队引擎服务器预期的令牌,请参阅 JSON Web 令牌和签发 JSON Web 令牌。
授权令牌提供对以下 Fleet Engine 服务的访问权限:
TripService
- 向 Consumer SDK 授予对行程详细信息(包括车辆位置、路线和预计到达时间)的访问权限。行程服务的授权令牌必须在令牌的authorization
标头中包含tripid:TRIP_ID
声明,其中TRIP_ID
是要共享的按需行程的行程 ID。VehicleService
- 向消费者 SDK 提供关于车辆大致位置的信息,以便显示车辆密度层并估算上车点预计到达时间。由于使用方 SDK 仅使用大致位置信息,因此车辆服务的授权令牌不需要vehicleid
声明。
什么是令牌?
对于从低信任环境进行的 API 方法调用,车队引擎要求使用由适当服务账号签名的 JSON Web 令牌 (JWT)。低信任环境包括智能手机和浏览器。JWT 来自您的服务器,这是一个完全可信的环境。系统会对 JWT 进行签名和加密,然后将其传递给客户端以进行后续服务器互动,直到 JWT 过期或失效。
您的后端应使用标准的应用默认凭据机制针对 Fleet Engine 进行身份验证和授权。请务必使用由相应服务账号签名的 JWT。如需查看服务账号角色的列表,请参阅 Fleet Engine 基础知识中的 Fleet Engine 服务账号角色。
相反,您的后端应使用标准应用默认凭据机制针对 Fleet Engine 进行身份验证和授权。
如需详细了解 JSON Web 令牌,请参阅 Fleet Engine 基础知识中的 JSON Web 令牌。
客户端如何获取令牌?
司机或消费者使用适当的授权凭据登录您的应用后,从该设备发出的任何更新都必须使用适当的授权令牌,这些令牌会将应用的权限传达给 Fleet Engine。
作为开发者,您的客户端实现应能够执行以下操作:
- 从您的服务器提取 JSON Web 令牌。
- 在令牌过期之前重复使用,以最大限度地减少令牌刷新。
- 在令牌过期时刷新令牌。
AuthTokenFactory
类会在位置信息更新时生成授权令牌。SDK 必须将令牌与更新信息打包在一起,以发送到 Fleet Engine。在初始化 SDK 之前,请确保您的服务器端实现可以颁发令牌。
如需详细了解 Fleet Engine 服务预期的令牌,请参阅为 Fleet Engine 颁发 JSON Web 令牌。
授权令牌提取程序示例
以下代码示例演示了如何实现授权令牌回调。
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
}
}
}