我有一个用Ktor做的API,我尝试按角色实现授权,如下所示:
internal class RoleBaseConfiguration(
var requiredRoles: Set<String> = emptySet()
)
internal val globalconfig = RoleBaseConfiguration()
internal val RoleAuthorizationPlugin = createApplicationPlugin(
name = "RoleAuthorizationPlugin",
createConfiguration = ::RoleBaseConfiguration
){
pluginConfig.apply{
on(AuthenticationChecked){ call ->
val jwtToken = call.request.headers["Authorization"]?.toJWT() ?: throw
Exception("Missing principal")
val roles =
JWTConfig.verifier.verify(jwtToken).getClaim("role")
.toString().roleToSet()
println("${globalconfig.requiredRoles} - $roles")
if(roles.intersect(globalconfig.requiredRoles).isEmpty()){
call.respondText("You don`t have access to this resource.", status =
HttpStatusCode.Unauthorized)
}
}
}
}
fun Route.withRole(role: String, build: Route.() -> Unit): Route {
return withRoles(role, build = build)
}
fun Route.withRoles(vararg roles: String, build: Route.() -> Unit): Route {
val authenticatedRoute = createChild(AuthorizationRouteSelector)
/*authenticatedRoute.install(RoleAuthorizationPlugin) {
this.requiredRoles = roles.toSet()
}*/
globalconfig.requiredRoles = roles.toSet()
authenticatedRoute.build()
return authenticatedRoute
}
object AuthorizationRouteSelector : RouteSelector() {
override fun evaluate(context: RoutingResolveContext, segmentIndex: Int):
RouteSelectorEvaluation {
return RouteSelectorEvaluation.Transparent
}
override fun toString(): String = "(authorize \"default\" )"
}
fun String.roleToSet(): Set<String>{
return split(",").map{ it.trim().replace("\"", "") }.toSet()
}
fun String.toJWT() = removePrefix("Bearer ")
然后在routes文件中,我调用withRole和withRoles方法,如下所示:
route("/auth") {
authenticate {
withRoles("user", "admin){
get("register"){
//Implementar el registro
}
}
}
withRole("admin"){
get("test"){
call.respond("Test")
}
}
}
当我用用户类型user请求/auth/register时,我得到401,println打印“[admin] - [user]”,据我所知,只有最后一次调用withRole或withRoles的角色被保存。
我一直在研究,但我找不到解决方案,使其正常工作.我想使用createRouteScopePlugin(...)而不是createApplicationPlugin(...),但事实证明,如果我使用第一个选项,我只能调用withRole或withRoles一次,如果我调用它多次抛出一个异常说,该插件已经安装.
1条答案
按热度按时间eeq64g8w1#
我在你的解决方案中看到了两个问题。第一,你使用了一个在路由之间共享的全局配置。第二,
AuthenticationChecked
钩子只在路由级别执行,但你的插件是应用程序范围的。我建议在插件的配置中存储所需的角色,并为每个授权范围安装插件。
以下是路由中插件使用的示例: