Авторизация и аутентификация в Kotlin: полный разбор
В современной веб-разработке на Kotlin вопросы безопасности стоят на первом месте. Авторизация (проверка прав доступа) и аутентификация (подтверждение личности пользователя) — ключевые механизмы, без которых не обходится ни одно приложение. В этой статье мы разберём, как реализовать эти процессы с помощью популярных библиотек: Ktor, Spring Security и JWT.
1. Основные понятия
- Аутентификация — процесс проверки, кто вы (логин/пароль, токен, OAuth).
- Авторизация — определение, что вам разрешено делать (роли, права доступа).
- JWT (JSON Web Token) — компактный способ передачи данных между сторонами в виде JSON-объекта, подписанного секретным ключом.
- Session — классический подход с хранением сессии на сервере.
2. Аутентификация с помощью Ktor (Kotlin Server)
Ktor — легковесный фреймворк от JetBrains, идеально подходящий для создания REST API на Kotlin. Встроенная поддержка аутентификации позволяет быстро настроить JWT, Basic Auth или OAuth.
Пример настройки JWT-аутентификации в Ktor:
// build.gradle.kts
dependencies {
implementation("io.ktor:ktor-server-auth-jwt:$ktorVersion")
}
// Application.kt
import io.ktor.server.auth.*
import io.ktor.server.auth.jwt.*
import com.auth0.jwk.JwkProviderBuilder
import java.util.*
fun Application.module() {
install(Authentication) {
jwt("auth-jwt") {
verifier(JwkProviderBuilder("https://your-issuer.com/.well-known/jwks.json")
.build()
.get("your-kid"))
validate { credential ->
if (credential.payload.audience.contains("my-app")) {
JWTPrincipal(credential.payload)
} else null
}
}
}
routing {
authenticate("auth-jwt") {
get("/secure") {
val principal = call.principal<JWTPrincipal>()
val username = principal?.payload?.getSubject()
call.respondText("Hello, $username!")
}
}
}
}
В этом примере мы используем JWTPrincipal для извлечения данных пользователя из токена. Ktor автоматически проверяет подпись и срок действия.
3. Авторизация через Spring Security
Spring Boot с Kotlin — мощное сочетание для enterprise-приложений. Spring Security предоставляет гибкую систему фильтров и аннотаций.
Базовая настройка с JWT:
// build.gradle.kts
dependencies {
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")
}
// SecurityConfig.kt
@Configuration
@EnableWebSecurity
class SecurityConfig(
private val jwtAuthenticationFilter: JwtAuthenticationFilter
) {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http
.csrf { it.disable() }
.sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) }
.authorizeHttpRequests { auth ->
auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
}
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter::class.java)
return http.build()
}
}
// JwtAuthenticationFilter.kt
@Component
class JwtAuthenticationFilter(
private val jwtService: JwtService
) : OncePerRequestFilter() {
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
val authHeader = request.getHeader("Authorization")
if (authHeader != null && authHeader.startsWith("Bearer ")) {
val token = authHeader.substring(7)
try {
val username = jwtService.extractUsername(token)
val userDetails = UserDetailsService.loadUserByUsername(username)
val authToken = UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.authorities
)
SecurityContextHolder.getContext().authentication = authToken
} catch (e: Exception) {
SecurityContextHolder.clearContext()
}
}
filterChain.doFilter(request, response)
}
}
Здесь мы реализовали stateless-аутентификацию: каждый запрос проверяется через JWT-фильтр. Роли задаются через hasRole().
4. Работа с JWT: генерация и валидация
Для работы с JWT в Kotlin удобно использовать библиотеку jjwt (Java JWT). Пример генерации токена:
// JwtService.kt
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.security.Keys
import java.util.*
@Service