You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Playframework Scala:Silhouette的JWTAuthenticator是否支持RS256微服务认证?

嘿,刚好我之前在基于Play Framework的Scala微服务集群里,用Silhouette实现过RS256算法的JWT认证,完全不用自己从零编写Authenticator,给你分享下具体的实现思路和步骤:

核心思路

Silhouette的JWTAuthenticator其实原生支持RS256,只是默认配置没指向这个算法,只要调整依赖、配置和组件绑定,就能直接用官方提供的实现,不用自己造轮子。

1. 调整依赖确保支持RS256

首先确保你用的是较新版本的Silhouette(推荐6.x+),然后在build.sbt里添加必要的JWT依赖,尤其是JJWT库(Silhouette底层依赖它处理JWT):

libraryDependencies ++= Seq(
  "com.mohiva" %% "play-silhouette" % "6.1.0",
  "com.mohiva" %% "play-silhouette-jwt" % "6.1.0",
  "io.jsonwebtoken" % "jjwt-api" % "0.11.5",
  "io.jsonwebtoken" % "jjwt-impl" % "0.11.5" % Runtime,
  "io.jsonwebtoken" % "jjwt-jackson" % "0.11.5" % Runtime
)

2. 配置RS256相关参数

application.conf里配置Silhouette的JWT设置,明确指定算法为RS256,同时配置密钥路径和其他JWT元数据:

silhouette {
  jwt {
    algorithm = "RS256"
    issuer = "your-internal-service-issuer"
    subject = "internal-microservice-communication"
    audience = ["service-a", "service-b", "service-c"] // 你的微服务列表
    expiresIn = 3600 // 令牌有效期,按需调整
    publicKeyPath = "/config/keys/public.key" // 建议放在统一配置目录
    privateKeyPath = "/config/keys/private.key"
  }
}

如果还没有RSA密钥对,可以用OpenSSL生成:

# 生成2048位私钥
openssl genrsa -out private.key 2048
# 从私钥导出公钥
openssl rsa -in private.key -pubout -out public.key

3. 绑定Silhouette的JWT组件

在你的Silhouette模块中,绑定官方的JWT相关组件即可,它会根据配置自动使用RS256算法:

import com.mohiva.play.silhouette.api._
import com.mohiva.play.silhouette.impl.authenticators._
import com.mohiva.play.silhouette.impl.util._
import play.api.Configuration
import play.api.libs.concurrent.AkkaGuiceSupport

class SilhouetteModule extends AbstractModule with AkkaGuiceSupport {
  override def configure(): Unit = {
    // 绑定JWT解析器和验证器
    bind[JWTParser].to[JWTParserImpl]
    bind[JWTValidator].to[JWTValidatorImpl]
    // 绑定JWT认证服务
    bind[JWTAuthenticatorService].toProvider[JWTAuthenticatorServiceProvider]
    // 绑定环境(根据你的用户模型调整)
    bind[Environment[User, JWTAuthenticator]].to[DefaultEnvironment[User, JWTAuthenticator]]
    // 其他必要的Silhouette绑定...
  }
}

这里的关键是JWTAuthenticatorServiceProvider会读取配置中的algorithm参数,自动初始化RS256的签名器和验证器,完全不用自己写逻辑。

4. 生成与验证令牌

生成JWT令牌

在服务端(比如认证服务),直接用JWTAuthenticatorService生成令牌即可,它会自动用RS256签名:

import com.mohiva.play.silhouette.impl.authenticators.JWTAuthenticator
import play.api.Configuration

class TokenService(
  authenticatorService: JWTAuthenticatorService,
  configuration: Configuration
)(implicit ec: ExecutionContext) {
  
  def generateTokenForService(loginInfo: LoginInfo): Future[String] = {
    val authenticator = JWTAuthenticator(
      loginInfo = loginInfo,
      issuer = configuration.get[String]("silhouette.jwt.issuer"),
      subject = Some("service-identity"),
      audience = Some(configuration.get[Seq[String]]("silhouette.jwt.audience")),
      expiresIn = configuration.get[FiniteDuration]("silhouette.jwt.expiresIn")
    )
    authenticatorService.create(authenticator).map(_.token)
  }
}

验证JWT令牌

在其他微服务中,用JWTAuthenticatorServiceretrieve方法验证请求头中的令牌:

import play.api.mvc._

class AuthAction(
  authenticatorService: JWTAuthenticatorService,
  silhouette: Environment[User, JWTAuthenticator]
)(implicit ec: ExecutionContext) extends ActionBuilder[Request, AnyContent] {
  
  override def invokeBlock[A](request: Request[A], block: Request[A] => Future[Result]): Future[Result] = {
    authenticatorService.retrieve(request).flatMap {
      case Some(authenticator) =>
        // 验证令牌有效性,比如检查受众、过期时间等
        silhouette.authenticatorService.validate(authenticator).flatMap {
          case Valid(_) => block(request)
          case Invalid(_) => Future.successful(Results.Unauthorized("Invalid token"))
        }
      case None => Future.successful(Results.Unauthorized("No token provided"))
    }
  }
}

然后在控制器中使用这个Action保护内部接口即可。

5. 内部微服务通信的小优化

  • 把JWT令牌放在Authorization: Bearer <token>请求头中,这是标准做法;
  • 建议将公钥放在统一配置中心(比如Consul、etcd),所有微服务从配置中心拉取公钥,避免每个服务都维护一份文件;
  • 因为是内部通信,可以适当延长令牌有效期,但也要根据安全需求调整。

内容的提问来源于stack exchange,提问作者ivanorone

火山引擎 最新活动