用户类型受限的路由功能,拦截器顺序错误

时间:2019-08-14 22:23:13

标签: kotlin ktor

我正在基于用户角色的身份验证。我的interceptors的执行顺序错误:用户角色,身份验证。需要切换它们,以便我可以访问UserTypeAuthentication中经过身份验证的用户Principal。当我调试代码时,拦截器以正确的顺序注册。管道似乎也处于正确的顺序。

class UserTypeAuthentication{
    class Configuration

    companion object Feature : ApplicationFeature<Application, Configuration, UserTypeAuthentication> {
        val userRestrict = PipelinePhase("UserTypeAuth")

        override val key = AttributeKey<UserTypeAuthentication>("UserTypeAuth")

        override fun install(pipeline: Application, configure: Configuration.() -> Unit): UserTypeAuthentication {
            return UserTypeAuthentication().apply { configure(configure) }
        }
    }

    fun interceptPipeline(
        pipeline: ApplicationCallPipeline,
        vararg types: JWTUserType
    ) {
        pipeline.insertPhaseAfter(ApplicationCallPipeline.Features, userRestrict)

        pipeline.intercept(userRestrict){
            val user = call.authentication.principal as AuthenticatedUser
            if (!types.contains(user.type)) {
                call.respond(HttpStatusCode.Unauthorized)
                finish()
            }
        }
    }

    private fun configure(configure: Configuration.() -> Unit) {}

}

fun Route.only(
    vararg types : JWTUserType,
    build: Route.() -> Unit
): Route {
    val authenticatedRoute = createChild(
        UserTypeRoute(types.toList().distinct().map { it.toString() })
    )

    application.feature(UserTypeAuthentication).interceptPipeline(authenticatedRoute, *types)
    authenticatedRoute.build()

    return authenticatedRoute
}

@Test
fun testMultipleConfigurationsNested() =  withTestApplication {
    application.install(CustomHeader)
    application.install(Authentication) {
        basic {
            validate {
                when(it.name){
                    "customer" -> AuthenticatedUser(1, JWTUserType.CUSTOMER)
                    "admin" -> AuthenticatedUser(2, JWTUserType.ADMIN)
                    else -> null
                }
            }
        }
    }

    application.install(UserTypeAuthentication)

    application.routing {
        authenticate {
            only(JWTUserType.CUSTOMER){
                route("/route") { handle { call.respondText("OK") } }
            }
        }
    }


    handleRequest(HttpMethod.Post, "/route") {
        addHeader(
            HttpHeaders.Authorization,
            HttpAuthHeader.Single("basic", Base64.getEncoder().encodeToString("customer:password".toByteArray())).render()
        )
    }.let { call ->
        assertEquals(HttpStatusCode.OK.value, call.response.status()?.value)
    }

    handleRequest(HttpMethod.Post, "/route") {
        addHeader(
            HttpHeaders.Authorization,
            HttpAuthHeader.Single("basic", Base64.getEncoder().encodeToString("admin:password".toByteArray())).render()
        )
    }.let { call ->
        assertEquals(HttpStatusCode.Unauthorized.value, call.response.status()?.value)
    }

}


谢谢您的任何想法:)

编辑:

我发现,如果我以前使用过,则该测试有效。因为authenticatedRoute应该始终插入FeaturesCall之间,所以使用之前和之后有什么区别吗?

//pipeline.insertPhaseAfter(ApplicationCallPipeline.Features,authenticatedRoute)
  pipeline.insertPhaseBefore(ApplicationCallPipeline.Call, authenticatedRoute)

0 个答案:

没有答案