Access control feature for Ktor Server
It is a very simple plugin for implementing access control feature in ktor application.
This is a legacy project for our old applications using ktor 1.6.8. We will refactor ktor-server-access-control in a new repository for ktor 2.0+ in the future.
Please see ShinonomeTN Public Maven Repository for repository urls and repository manual.
Maven:
<dependency>
<groupId>com.shinonometn</groupId>
<artifactId>ktor-server-access-control</artifactId>
<version>${release-version}</version>
</dependency>
install(AccessControl) {
addMetaProvider("App Token") {
val token = call.request.header["APP-TOKEN"] ?: return@provider
it.put(token) // Put anything you want into AccessControlContext
}
}
// In route config
routing {
// If call satisfy some condition, accept it, or not, reject.
accessControl({ if (meta == meta<String>()) accept() else reject() }) {
get {
val accessControlContext = call.accessControl
val token = accessControl.meta<String>()!!
call.respond("Hello world! You have token $token")
}
}
}
install(AccessControl) {
unauthorized {
// Get reject reasons from AccessControlContext
val reasons : Map<String,String> = rejectReasons()
call.respond(HttpStatusCode.Unauthorized, reasons)
}
}
accessControl()
takes a lambda as it's first parameter. You can create and save it for later use,
or event combining those lambda functions.
val requireSession = AccessControlChecker { if(meta<UserSession>() != null) accepe() else reject() }
val requireAdmin = AccessControlChecker { if(isAdmin()) accept() else reject() }
val requireLoggedIn = AccessControlChecker { if(isSessionLoggedIn()) accept() else reject() }
routing {
accessControl(requireSession or requireLoggedIn) {
get("/homepage") {
call.respond("Hello User!")
}
}
accessControl(requireSession and requireAdmin) {
get("/admin") {
call.respond("Hello admin!")
}
}
accessControl(requireLoggedIn.not()) {
post("/logout") {
call.respond("You are logged out.")
}
}
}
Information of AccessControlContext can access via interface AccessControlMetaSnapshot
.
You can add extension function to do some useful things such as check user session state.
fun AccessControlMetaSnapshot.isUserLoggedIn() : Boolean {
val session = metas<UserSession>() ?: return false
return session.isLoggedIn()
}
val requireLoggedIn = AccessControlChecker { if(isUserLoggedIn()) accept() else reject() }
routing {
accessControl(requireLoggedIn) {
get("/homepage") {
call.respond("Hello User!")
}
}
}
You can access checkAccessControl()
from ApplicationCall and do additional checks for permissions.
val requireAdmin = AccessControlChecker { if(isAdmin()) accept() else reject() }
val requireLoggedIn = AccessControlChecker { if(isSessionLoggedIn()) accept() else reject() }
routing {
accessControl(requireLoggedIn) {
get("/admin") {
val context = call.checkAccessControl(requireAdmin)
if(context.result() is AccessControlCheckerResult.Pass)
return@get call.respond("Welcome, admin!")
call.respond(HttpStatusCode.Forbidden, "You shall not pass!")
}
}
}