Kotlin中的JWT令牌:jjwt库完整指南
在现代Web开发中,JWT(JSON Web Tokens)已成为客户端与服务器之间进行身份验证和信息交换的标准。在Kotlin生态系统中,尤其是在使用Spring Boot或Ktor构建后端应用时,经常需要处理JWT。本文将介绍io.jsonwebtoken(jjwt)库——Java/Kotlin中最流行的JWT处理工具。
什么是JWT?
JWT是一种紧凑的、URL安全的方式,用于在双方之间表示声明(claims)。令牌由三部分组成,以点号分隔:
- Header — 头部,包含令牌类型和签名算法(例如HS256、RS256)。
- Payload — 有效载荷,包含声明(claims):
sub(主题)、iat(签发时间)、exp(过期时间)以及自定义数据。 - Signature — 签名,使用密钥或密钥对生成。
引入库
要在Kotlin中使用JWT,我们将使用jjwt(io.jsonwebtoken)。在build.gradle.kts中添加依赖:
dependencies { implementation("io.jsonwebtoken:jjwt-api:0.12.6") runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.6") runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.6") // 用于JSON解析}生成JWT令牌
要创建令牌,需要设置密钥、声明并签名令牌。Kotlin示例:
import io.jsonwebtoken.Jwtsimport io.jsonwebtoken.security.Keysimport java.util.Dateimport javax.crypto.SecretKey
fun generateToken(userId: String, secret: String): String { val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray()) val now = Date() val expiration = Date(now.time + 3600_000) // +1小时 return Jwts.builder() .subject(userId) .issuedAt(now) .expiration(expiration) .claim("role", "USER") .signWith(key) .compact()}验证和解析JWT
收到客户端令牌后,需要验证其签名和有效期。使用Jwts.parser():
import io.jsonwebtoken.JwtExceptionimport io.jsonwebtoken.Jwtsimport io.jsonwebtoken.security.Keysimport javax.crypto.SecretKey
fun validateToken(token: String, secret: String): Boolean { return try { val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray()) Jwts.parser() .verifyWith(key) .build() .parseSignedClaims(token) true } catch (e: JwtException) { false }}
fun extractUserId(token: String, secret: String): String? { return try { val key: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray()) val claims = Jwts.parser() .verifyWith(key) .build() .parseSignedClaims(token) .payload claims.subject } catch (e: Exception) { null }}使用自定义声明
您可以在有效载荷中添加任意自定义数据。例如,存储用户的邮箱或角色:
fun generateTokenWithCustomClaims(userId: String, email: String, secret: String): String { val key = Keys.hmacShaKeyFor(secret.toByteArray()) return Jwts.builder() .subject(userId) .claim("email", email) .claim("isAdmin", false) .issuedAt(Date()) .expiration(Date(System.currentTimeMillis() + 3600_000)) .signWith(key) .compact()}
fun extractCustomClaim(token: String, secret: String): String? { val key = Keys.hmacShaKeyFor(secret.toByteArray())