【问题标题】:How Silhouette JWT token keeps valid in stateless mode?Silhouette JWT 令牌如何在无状态模式下保持有效?
【发布时间】:2016-07-30 22:15:59
【问题描述】:

我正在开发一个项目并使用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 {

请注意文档的这一部分

如果验证器 DAO 被停用,那么无状态方法将 使用。但请注意*,您将失去无效的可能性 一个智威汤逊。

所以它就像他们说的那样工作。当我将None 作为dao 参数的值传递时,即使我关闭了应用程序,生成的令牌也会保持有效。但是如果没有后备存储,这些令牌如何保持有效?当我再次启动应用程序并使用相同的令牌时,它会对用户进行身份验证。我不知道它是怎么做到的。你能解释一下吗?

【问题讨论】:

  • 这很简单。您使用已知的盐和算法组合对令牌的内容进行编码。 JWT 令牌具有已知结构,使用 HMAC 或 RSA 编码。服务器可以以无状态方式解密令牌,只要它们知道编码密钥(HMAC 的秘密密钥)和 RSA 的密钥对。
  • 是的,如果我想得更努力一点,我会猜想显然令牌应该包含有关链接帐户的信息。服务器可以轻松解密令牌的事实对我来说并不简单。您能否将您的评论作为答案,以便我接受?

标签: scala playframework silhouette


【解决方案1】:

这很简单。您使用已知的盐和算法组合对令牌的内容进行编码。 JWT 令牌具有已知结构,使用 HMAC 或 RSA 编码。服务器可以以无状态方式解密令牌,只要它们知道编码密钥(HMAC 的密钥)和 RSA 的密钥对。

如果您想变聪明并检查内部结构,您甚至可以自己制作。 JWT 是标准化的,按照惯例,该帐户通常在 iss 字段下可用。例如,在 Google Cloud 中,iss 是您的 Google 服务帐户电子邮件,因此他们可以知道您是谁。

进一步探索,您可以创建自己的 session 对象并将其编码为令牌。

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 或标头中使用此令牌的字符串值,并且每个服务器只要知道someSharedKey 的值,就可以无状态地验证令牌并提取用户信息,用于执行编码的秘密。

【讨论】:

    猜你喜欢
    • 2015-02-05
    • 2021-04-13
    • 2019-04-23
    • 1970-01-01
    • 2016-12-03
    • 2021-09-25
    • 2019-03-19
    • 2019-02-02
    相关资源
    最近更新 更多