Use Keycloak-Realm-Roles for authorization

This commit is contained in:
Hartmut Bauer committed 2026-02-10 18:01:22 +01:00
1 parent f8b4215233
commit c4400a0334
4 files changed
+54 -5

No files matched your search

@@ -0,0 +1,33 @@
package books
import books.model.BookRepository
import io.ktor.http.*
import io.ktor.server.auth.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import net.keinekekse.app.UserRoles
import org.koin.ktor.ext.inject
fun Route.booksRoute() {
val repository: BookRepository by inject<BookRepository>()
authenticate(UserRoles.BOOKS_USER.roleName) {
route("/books") {
get("/books") {
// call.respondText("Test DB route")
val books = repository.allBooks()
call.respond(books)
}
get("/book/{id}") {
// TODO safe toInt conv
val id = call.parameters["id"]!!.toInt()
repository.bookById(id)?.let { call.respond(it) }
?: call.respondText(
"Book with id $id not found",
status = HttpStatusCode.NotFound
)
}
}
}
}
@@ -1,18 +1,19 @@
package net.keinekekse.app.server.config package net.keinekekse.app.server.config
import books.booksRoute
import io.github.oshai.kotlinlogging.KotlinLogging import io.github.oshai.kotlinlogging.KotlinLogging
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.auth.* import io.ktor.server.auth.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
import net.keinekekse.app.UserRoles
import net.keinekekse.app.server.VERSION import net.keinekekse.app.server.VERSION
import net.keinekekse.app.server.testdb.testDbRoute
private val logger = KotlinLogging.logger {} private val logger = KotlinLogging.logger {}
fun Application.configureRouting() { fun Application.configureRouting() {
routing { routing {
authenticate("auth-KC") { authenticate(UserRoles.BOOKS_USER.roleName) {
get("/") { get("/") {
val principal = call.principal<AppPrincipal>() val principal = call.principal<AppPrincipal>()
call.respondText("user: ${principal?.userId}") call.respondText("user: ${principal?.userId}")
@@ -24,6 +25,6 @@ fun Application.configureRouting() {
} }
} }
testDbRoute() booksRoute()
} }
} }
@@ -7,6 +7,7 @@ import io.ktor.server.application.*
import io.ktor.server.auth.* import io.ktor.server.auth.*
import io.ktor.server.auth.jwt.* import io.ktor.server.auth.jwt.*
import io.ktor.server.response.* import io.ktor.server.response.*
import net.keinekekse.app.UserRoles
import java.net.URI import java.net.URI
private val logger = KotlinLogging.logger {} private val logger = KotlinLogging.logger {}
@@ -25,7 +26,8 @@ fun Application.configureSecurity() {
val issuer = "$keycloakUrl/$keycloakRealm" val issuer = "$keycloakUrl/$keycloakRealm"
authentication { authentication {
jwt("auth-KC") { for (role in UserRoles.entries) {
jwt(role.roleName) {
verifier( verifier(
UrlJwkProvider(URI(certUrl).toURL()), issuer UrlJwkProvider(URI(certUrl).toURL()), issuer
) { ) {
@@ -36,7 +38,11 @@ fun Application.configureSecurity() {
call.respond(HttpStatusCode.Unauthorized, "Token is not valid or has expired") call.respond(HttpStatusCode.Unauthorized, "Token is not valid or has expired")
} }
validate { credential -> validate { credential ->
AppPrincipal(credential) val principal = AppPrincipal(credential)
if (principal.roles.contains(role.roleName) ||
principal.roles.contains(UserRoles.ADMIN.roleName)
) principal else null
}
} }
} }
} }
@@ -0,0 +1,9 @@
package net.keinekekse.app
enum class UserRoles(val roleName: String) {
ADMIN("admin"),
BOOKS_ADMIN("books-admin"),
BOOKS_USER("books-user"),
BOOKS_EDITOR("books-editor")
}