Авторизация и аутентификация в Kotlin: Ktor, JWT и Spring Security

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Авторизация и аутентификация в 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                    

Рекомендаций