Kotlin 中的授权与认证:完整指南
在现代 Kotlin Web 开发中,应用程序的安全性始于正确实现认证(验证用户身份)和授权(验证访问权限)。在本文中,我们将探讨在 Spring Boot 和 Ktor 平台上实现这些机制的主要方法、库和工具。
基本概念
在进入代码之前,我们先了解一些术语:
- 认证 — 验证用户是否为其所声称的身份的过程(通常通过登录名/密码、令牌或生物识别)。
- 授权 — 确定已认证用户的访问权限(例如,访问特定路由或数据)。
- JWT(JSON Web Token) — 一种紧凑且自包含的令牌,用于在各方之间传输数据。
- BCrypt — 一种带盐的密码哈希算法,能够抵抗暴力攻击。
在 Spring Boot 中使用 JWT 进行认证
Spring Security 为认证提供了强大的基础设施。让我们看看如何使用 io.jsonwebtoken:jjwt 库实现 JWT 认证。
// build.gradle.ktsdependencies { implementation("org.springframework.boot:spring-boot-starter-security") implementation("io.jsonwebtoken:jjwt-api:0.12.3") runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.3") runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.3")}创建一个用于处理 JWT 的工具类:
import io.jsonwebtoken.*import io.jsonwebtoken.security.Keysimport org.springframework.stereotype.Componentimport java.security.Keyimport java.util.*
@Componentclass JwtUtil { private val secretKey: Key = Keys.secretKeyFor(SignatureAlgorithm.HS256) private val expirationMs: Long = 3600000 // 1 小时
fun generateToken(username: String): String { return Jwts.builder() .subject(username) .issuedAt(Date()) .expiration(Date(System.currentTimeMillis() + expirationMs)) .signWith(secretKey) .compact() }
fun extractUsername(token: String): String? { return try { Jwts.parser().verifyWith(secretKey).build() .parseSignedClaims(token).payload.subject } catch (e: Exception) { null } }
fun validateToken(token: String): Boolean { return try { Jwts.parser().verifyWith(secretKey).build() .parseSignedClaims(token) true } catch (e: JwtException) { false } }}Spring Security 的认证过滤器
现在创建一个过滤器,用于拦截请求并验证 JWT 令牌:
import jakarta.servlet.FilterChainimport jakarta.servlet.http.HttpServletRequestimport jakarta.servlet.http.HttpServletResponseimport org.springframework.security.authentication.UsernamePasswordAuthenticationTokenimport org.springframework.security.core.context.SecurityContextHolderimport org.springframework.security.web.authentication.WebAuthenticationDetailsSourceimport org.springframework.stereotype.Componentimport org.springframework.web.filter.OncePerRequestFilter
@Componentclass JwtAuthFilter( private val jwtUtil: JwtUtil, private val userDetailsService: org.springframework.security.core.userdetails.UserDetailsService) : OncePerRequestFilter() {
override fun doFilterInternal( request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain ) { val authHeader = request.getHeader("Authorization") if (authHeader == null || !authHeader.startsWith("Bearer ")) { chain.doFilter(request, re