在Quarkus(Kotlin)中为静态资源添加HTTP拦截器的方法
Quarkus默认会让Vert.x静态资源处理器优先处理静态资源请求,这些请求不会进入JAX-RS的过滤器链,所以你用@Provider标注的ContainerRequestFilter只能捕获API请求,碰不到静态资源的请求。下面给你三种可行的解决方案:
方案一:用Vert.x全局HTTP过滤器(推荐)
直接基于Quarkus底层的Vert.x路由,在静态资源处理前插入Cookie校验逻辑,能拦截所有请求(包括静态资源)。
代码实现:
创建一个实现VertxRouterCustomizer的类,自定义路由拦截规则:
import io.quarkus.vertx.http.runtime.VertxRouterCustomizer import io.vertx.ext.web.Router import io.vertx.ext.web.RoutingContext import jakarta.enterprise.context.ApplicationScoped @ApplicationScoped class StaticResourceAuthFilter : VertxRouterCustomizer { override fun customize(router: Router) { // 拦截/books/examplediary下的所有请求,优先级高于静态资源处理器 router.route("/books/examplediary/*").handler(this::validateCookie) } private fun validateCookie(ctx: RoutingContext) { // 获取指定Cookie val authCookie = ctx.request().getCookie("your_cookie_name") if (authCookie == null) { // Cookie不存在,返回403禁止访问 ctx.response() .setStatusCode(403) .putHeader("Content-Type", "text/plain") .end("Access denied") return } // Cookie校验通过,继续处理请求 ctx.next() } }
静态资源默认放在src/main/resources/META-INF/resources/目录下,确保你的books/examplediary目录在这个路径里。
方案二:通过JAX-RS资源类提供受保护的静态资源
把需要保护的静态资源交给JAX-RS处理,这样就能复用你原来的JAX-RS过滤器。
步骤1:创建JAX-RS资源类
import jakarta.ws.rs.GET import jakarta.ws.rs.Path import jakarta.ws.rs.PathParam import jakarta.ws.rs.core.Response import java.net.URL @Path("/books/examplediary") class ProtectedStaticResource { @GET @Path("/{fileName:.*}") fun getProtectedResource(@PathParam("fileName") fileName: String): Response { // 加载静态资源文件 val resourceUrl: URL? = Thread.currentThread() .contextClassLoader .getResource("META-INF/resources/books/examplediary/$fileName") return resourceUrl?.let { Response.ok(it.openStream()).build() } ?: Response.status(404).entity("Resource not found").build() } }
步骤2:调整原有过滤器的路径匹配
修改CookieValidationFilter,让它匹配JAX-RS处理的静态资源路径:
import jakarta.ws.rs.container.ContainerRequestContext import jakarta.ws.rs.container.ContainerRequestFilter import jakarta.ws.rs.core.Response import jakarta.ws.rs.ext.Provider @Provider class CookieValidationFilter : ContainerRequestFilter { override fun filter(requestContext: ContainerRequestContext) { val requestPath = requestContext.uriInfo.path // 匹配所有/examplediary下的资源请求 if (requestPath.startsWith("/books/examplediary/")) { val authCookie = requestContext.cookies["your_cookie_name"] if (authCookie == null) { requestContext.abortWith( Response.status(Response.Status.FORBIDDEN) .entity("Access denied") .build() ) } } } }
方案三:用Quarkus Security模块做路径保护
借助Quarkus的Security组件,通过配置或注解保护静态资源路径,配合Cookie认证机制(需要配置对应的Cookie认证器)。
示例配置(application.properties)
# 保护指定静态资源路径,要求用户已认证 quarkus.security.authz.paths."/books/examplediary/*".roles-allowed=authenticated # 指定使用自定义Cookie认证机制 quarkus.security.authentication=custom quarkus.security.custom-auth-mechanism-implementation=com.yourpackage.CookieAuthMechanism
自定义Cookie认证器示例
import io.quarkus.security.identity.AuthenticationRequestContext import io.quarkus.security.identity.IdentityProvider import io.quarkus.security.identity.SecurityIdentity import io.quarkus.security.runtime.QuarkusSecurityIdentity import io.smallrye.mutiny.Uni import jakarta.enterprise.context.ApplicationScoped import jakarta.ws.rs.core.Cookie @ApplicationScoped class CookieAuthMechanism : IdentityProvider<CookieAuthenticationRequest> { override fun getRequestType(): Class<CookieAuthenticationRequest> { return CookieAuthenticationRequest::class.java } override fun authenticate( request: CookieAuthenticationRequest, context: AuthenticationRequestContext ): Uni<SecurityIdentity> { val authCookie = request.cookies["your_cookie_name"] return if (authCookie != null && isValidCookie(authCookie.value)) { // 校验通过,构建已认证的身份信息 Uni.createFrom().item( QuarkusSecurityIdentity.builder() .setPrincipal(java.security.Principal { "authenticated-user" }) .addRole("authenticated") .build() ) } else { // 校验失败,返回空表示认证不通过 Uni.createFrom().nullItem() } } private fun isValidCookie(cookieValue: String): Boolean { // 这里实现你的Cookie值校验逻辑(比如解密、验证签名) return cookieValue.isNotEmpty() } } // 自定义认证请求载体类 class CookieAuthenticationRequest(val cookies: Map<String, Cookie>)
内容的提问来源于stack exchange,提问作者Nitish
相关产品推荐
相关产品推荐

