Scala 语言 实战 Play 框架实现 JWT 鉴权 登录 /token 刷新 / 权限验证

Scala阿木 发布于 2025-06-10 14 次阅读


Scala 语言实战 Play 框架实现 JWT 鉴权

随着互联网的快速发展,安全性成为系统设计中的重要一环。JWT(JSON Web Token)是一种轻量级的安全认证方式,常用于用户登录、会话管理等场景。本文将围绕Scala语言和Play框架,详细介绍如何实现JWT鉴权,包括登录、token刷新和权限验证。

环境准备

在开始之前,请确保以下环境已准备好:

- Scala 2.13.x 或更高版本
- Play Framework 2.8.x 或更高版本
- Java 11 或更高版本
- sbt 1.5.x 或更高版本

创建 Play 项目

使用 sbt 创建一个新的 Play 项目:

shell
sbt new playframework/play-java-seed.g8

然后,进入项目目录并添加依赖:

scala
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-java" % "2.8.x",
"io.jsonwebtoken" % "jjwt" % "0.11.2"
)

JWT 鉴权原理

JWT 是一种基于 JSON 的开放标准(RFC 7519),用于在各方之间安全地传输信息。它由三部分组成:

1. 头部(Header):描述 JWT 的类型和签名算法。
2. 载荷(Payload):包含用户信息,如用户名、角色等。
3. 签名(Signature):使用头部中的算法和密钥对前两部分进行签名,确保 JWT 的完整性和真实性。

实现登录

在 Play 项目中,首先需要创建一个登录接口,用于生成 JWT。

1. 创建 LoginController

在 `app/controllers` 目录下创建 `LoginController`:

scala
package controllers

import javax.inject.Inject
import play.api.mvc._
import scala.concurrent.Future

class LoginController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
def login(username: String, password: String): Future[Result] = {
// 验证用户名和密码
if (username == "admin" && password == "admin") {
// 生成 JWT
val token = createToken("admin")
Ok(token)
} else {
BadRequest("Invalid username or password")
}
}

private def createToken(username: String): String = {
val secretKey = "your_secret_key"
val algorithm = "HS256"
val payload = Map(
"username" -> username,
"iat" -> System.currentTimeMillis() / 1000,
"exp" -> System.currentTimeMillis() / 1000 + 3600
)
val token = JwtHelper.createToken(secretKey, algorithm, payload)
token
}
}

2. 创建 JwtHelper

在 `app/utils` 目录下创建 `JwtHelper`:

scala
package utils

import io.jsonwebtoken.{JwtBuilder, Jwts}
import java.util.Date

object JwtHelper {
def createToken(secretKey: String, algorithm: String, payload: Map[String, Any]): String = {
val nowMillis = System.currentTimeMillis()
val now = new Date(nowMillis)
val exp = new Date(nowMillis + 3600000) // 1小时后过期

val builder: JwtBuilder = Jwts.builder()
.setIssuedAt(now)
.setExpiration(exp)
.signWith(SignatureAlgorithm.HS256, secretKey)

payload.foreach { case (key, value) => builder.setClaim(key, value) }

builder.compact()
}
}

实现token刷新

在 Play 项目中,实现 token 刷新需要创建一个刷新接口,用于生成新的 JWT。

1. 创建 RefreshController

在 `app/controllers` 目录下创建 `RefreshController`:

scala
package controllers

import javax.inject.Inject
import play.api.mvc._
import scala.concurrent.Future

class RefreshController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
def refresh(token: String): Future[Result] = {
// 验证 token
if (JwtHelper.validateToken(token)) {
// 生成新的 JWT
val newToken = JwtHelper.createToken("admin")
Ok(newToken)
} else {
BadRequest("Invalid token")
}
}
}

2. 修改 JwtHelper

在 `app/utils/JwtHelper` 中添加 `validateToken` 方法:

scala
object JwtHelper {
// ... (其他方法)

def validateToken(token: String): Boolean = {
val secretKey = "your_secret_key"
val algorithm = "HS256"
try {
Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody
true
} catch {
case _ => false
}
}
}

实现权限验证

在 Play 项目中,实现权限验证需要拦截器(Interceptor)。

1. 创建 AuthInterceptor

在 `app/controllers` 目录下创建 `AuthInterceptor`:

scala
package controllers

import javax.inject.Inject
import play.api.mvc._
import scala.concurrent.Future

class AuthInterceptor @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
def apply[A](action: Request[A] => Future[Result]): Request[A] => Future[Result] = {
request =>
// 获取 token
val token = request.headers.get("Authorization").map(_.split(" ")(1))
if (token.isDefined && JwtHelper.validateToken(token.get)) {
action(request)
} else {
Unauthorized("Invalid token")
}
}
}

2. 配置拦截器

在 `app/http` 目录下创建 `Application`:

scala
package http

import javax.inject.Inject
import play.api.mvc._
import scala.concurrent.Future

class Application @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
override val routes: Route = {
// 添加拦截器
new AuthInterceptor()(routes)
}
}

总结

本文介绍了如何使用 Scala 语言和 Play 框架实现 JWT 鉴权。通过创建登录接口、token刷新接口和权限验证拦截器,实现了用户登录、token刷新和权限验证功能。在实际项目中,可以根据需求调整和优化代码,以满足不同的业务场景。