Silhouette JWT 令牌如何在无状态模式下保持有效?
How Silhouette JWT token keeps valid in stateless mode?
我正在开发一个项目并使用 Silhouette 身份验证框架。
对于来自浏览器 UI 的常规请求,我使用 CookieAuthenticator,对于 REST API 请求,我使用 JWTAuthenticator。
这是带有文档的 Silhouette 源代码的一部分,这让我觉得我不完全理解这东西到底是如何工作的:
/**
* The service that handles the JWT authenticator.
*
* If the authenticator DAO is deactivated then a stateless approach will be used. But note
* that you will loose the possibility to invalidate a JWT.
*
* @param settings The authenticator settings.
* @param dao The DAO to store the authenticator. Set it to None to use a stateless approach.
* @param idGenerator The ID generator used to create the authenticator ID.
* @param clock The clock implementation.
* @param executionContext The execution context to handle the asynchronous operations.
*/
class JWTAuthenticatorService(
settings: JWTAuthenticatorSettings,
dao: Option[AuthenticatorDAO[JWTAuthenticator]],
idGenerator: IDGenerator,
clock: Clock)(implicit val executionContext: ExecutionContext)
extends AuthenticatorService[JWTAuthenticator]
with Logger {
注意文档的这一部分
If the authenticator DAO is deactivated then a stateless approach will
be used. But note * that you will loose the possibility to invalidate
a JWT.
所以它确实像他们说的那样工作。当我将 None
作为 dao
参数的值传递时,即使我关闭了应用程序,生成的令牌也会保持有效。但是如果没有后备存储,这些令牌如何保持有效?当我再次启动应用程序并使用相同的令牌时,它会对用户进行身份验证。我不知道它是怎么做到的。你能解释一下吗?
很简单。您使用已知的盐和算法组合对令牌的内容进行编码。 JWT 令牌具有已知结构,使用 HMAC 或 RSA 编码。例如,服务器可以以无状态方式解密令牌,只要他们知道编码密钥(HMAC 的密钥)和 RSA 的密钥对。
如果您想变聪明并检查内部结构,您甚至可以自己制作。 JWT 是标准化的,按照惯例,该帐户通常在 iss
字段下可用。例如,在 Google Cloud 中,iss
是您的 Google 服务帐户电子邮件,因此他们可以知道您是谁。
进一步探索,您可以制作自己的 session
object 并将其编码为令牌。
case class Session(user: UUID, timestamp: String, email: String)
// This is roughly the process used.
object TokenEncoder {
val secret = Play.current.configuration.getString("encryption.key")
def encode(session: Session): String = {
// The below line is just to make a point.
AES.encrypt(Json.toJson(session), someSharedKey)
}
def decode(str: String): Option[Session] = {
Json.parse(AES.decrypt(str, someSharedKey)).asOpt[Session]
}
}
然后可以在 cookie 或 header 中使用此令牌的字符串值以防跨服务器请求,并且每个服务器都可以无状态地验证令牌并提取用户信息,只要他们知道someSharedKey
的值,用于执行编码的秘密。
我正在开发一个项目并使用 Silhouette 身份验证框架。 对于来自浏览器 UI 的常规请求,我使用 CookieAuthenticator,对于 REST API 请求,我使用 JWTAuthenticator。 这是带有文档的 Silhouette 源代码的一部分,这让我觉得我不完全理解这东西到底是如何工作的:
/**
* The service that handles the JWT authenticator.
*
* If the authenticator DAO is deactivated then a stateless approach will be used. But note
* that you will loose the possibility to invalidate a JWT.
*
* @param settings The authenticator settings.
* @param dao The DAO to store the authenticator. Set it to None to use a stateless approach.
* @param idGenerator The ID generator used to create the authenticator ID.
* @param clock The clock implementation.
* @param executionContext The execution context to handle the asynchronous operations.
*/
class JWTAuthenticatorService(
settings: JWTAuthenticatorSettings,
dao: Option[AuthenticatorDAO[JWTAuthenticator]],
idGenerator: IDGenerator,
clock: Clock)(implicit val executionContext: ExecutionContext)
extends AuthenticatorService[JWTAuthenticator]
with Logger {
注意文档的这一部分
If the authenticator DAO is deactivated then a stateless approach will be used. But note * that you will loose the possibility to invalidate a JWT.
所以它确实像他们说的那样工作。当我将 None
作为 dao
参数的值传递时,即使我关闭了应用程序,生成的令牌也会保持有效。但是如果没有后备存储,这些令牌如何保持有效?当我再次启动应用程序并使用相同的令牌时,它会对用户进行身份验证。我不知道它是怎么做到的。你能解释一下吗?
很简单。您使用已知的盐和算法组合对令牌的内容进行编码。 JWT 令牌具有已知结构,使用 HMAC 或 RSA 编码。例如,服务器可以以无状态方式解密令牌,只要他们知道编码密钥(HMAC 的密钥)和 RSA 的密钥对。
如果您想变聪明并检查内部结构,您甚至可以自己制作。 JWT 是标准化的,按照惯例,该帐户通常在 iss
字段下可用。例如,在 Google Cloud 中,iss
是您的 Google 服务帐户电子邮件,因此他们可以知道您是谁。
进一步探索,您可以制作自己的 session
object 并将其编码为令牌。
case class Session(user: UUID, timestamp: String, email: String)
// This is roughly the process used.
object TokenEncoder {
val secret = Play.current.configuration.getString("encryption.key")
def encode(session: Session): String = {
// The below line is just to make a point.
AES.encrypt(Json.toJson(session), someSharedKey)
}
def decode(str: String): Option[Session] = {
Json.parse(AES.decrypt(str, someSharedKey)).asOpt[Session]
}
}
然后可以在 cookie 或 header 中使用此令牌的字符串值以防跨服务器请求,并且每个服务器都可以无状态地验证令牌并提取用户信息,只要他们知道someSharedKey
的值,用于执行编码的秘密。