Kotlin 中的 OAuth 2.0 和 JWT 授权:面向初学者
现代 Web 应用程序和 API 很少能离开认证和授权系统。该领域最流行的两个标准是 OAuth 2.0 和 JWT(JSON Web Token)。在本文中,我们将探讨如何使用这些技术在 Kotlin 中实现授权。本材料面向熟悉 Kotlin 语言和 Spring Boot 框架基础的初学者开发者。
什么是 OAuth 2.0 和 JWT?
在编写代码之前,理解理论很重要。
OAuth 2.0 是一种授权协议,它允许应用程序在不传递登录名和密码的情况下获得对用户资源的有限访问权限。想象一下,您通过“使用 Google 登录”进入一个网站——这就是 OAuth 2.0。
JWT 是一种紧凑且自包含的令牌格式。它由三部分组成:头部(header)、有效载荷(payload)和签名(signature)。JWT 通常与 OAuth 2.0 一起使用,用于传递认证信息。
OAuth 2.0 的主要流程:
- 授权码流程(Authorization Code Flow) — 用于服务器端应用程序(最安全)
- 客户端凭证流程(Client Credentials Flow) — 用于服务器到服务器的通信
- 隐式流程(Implicit Flow) — 已过时,不推荐使用
- 资源所有者密码流程(Resource Owner Password Flow) — 仅当您信任客户端时使用
在本文中,我们将重点介绍客户端凭证流程,因为它最容易理解,并且经常用于微服务中。
在 Kotlin 中配置 Spring Boot 项目
创建一个支持 Kotlin 的新 Spring Boot 项目。在 build.gradle.kts 中添加必要的依赖项:
dependencies { implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server") implementation("io.jsonwebtoken:jjwt-api:0.11.5") runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5") runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5") implementation("com.fasterxml.jackson.module:jackson-module-kotlin")}这些依赖项提供了对 Spring Security、OAuth 2.0 Resource Server 以及用于处理 JWT 的 JJWT 库的支持。
在 Kotlin 中创建 JWT 令牌
编写一个用于生成和验证 JWT 的服务。这是我们授权的基础。
import io.jsonwebtoken.Jwtsimport io.jsonwebtoken.SignatureAlgorithmimport io.jsonwebtoken.security.Keysimport org.springframework.stereotype.Serviceimport java.util.Date
@Serviceclass JwtService { private val secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256) private val expirationMs = 3600000L // 1 小时
fun generateToken(clientId: String): String { val now = Date() val expiryDate = Date(now.time + expirationMs)
return Jwts.builder() .setSubject(clientId) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(secretKey) .compact() }
fun validateToken(token: String): Boolean { return try { Jwts.parserBuilder() .setSigningKey(secretKey) .build() .parseClaimsJws(token) true } catch (e: Exception) { false } }
fun getClientIdFromToken(token: String): String { val claims = Jwts.parserBuilder() .setSigningKey(secretKey) .build() .parseClaimsJws(token) .body return claims.subject }}在这个服务中,我们使用了一个对称密钥。在生产环境中,最好使用非对称加密(RS256)和