You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring WebFlux注解式控制器中按处理器方法拦截请求

当然可以实现!Spring WebFlux虽然是响应式架构,但完全能复刻你在Spring MVC里的权限校验逻辑,甚至更贴合响应式的设计。下面我就给你一步步拆解怎么适配到注解式控制器上:

1. 保留原有自定义注解和枚举

你的@Auth注解和AuthType枚举可以直接复用,不用做任何修改:

enum class AuthType {
    ALLOW, ADMIN
}

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Auth(val value: AuthType = AuthType.ALLOW)

2. 替换HandlerInterceptor为WebFilter

Spring WebFlux里没有HandlerInterceptorAdapter,替代方案是使用全局WebFilter——它能拦截所有请求,并且可以获取到注解式控制器对应的HandlerMethod,完美对应你原来的拦截器逻辑。

这里是适配后的响应式版本:

@Component
class AccessFilter : WebFilter {

    // 假设你有用户服务用来解析令牌和查询用户
    @Autowired
    private lateinit var userService: UserService

    override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
        // 获取当前请求匹配的处理器方法
        val handlerMethod = exchange.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE) as? HandlerMethod
            ?: return chain.filter(exchange) // 非注解控制器请求,直接放行

        // 优先取方法上的@Auth注解,没有则取类上的
        val authAnnotation = handlerMethod.method.getAnnotation(Auth::class.java)
            ?: handlerMethod.beanType.getAnnotation(Auth::class.java)
            ?: return chain.filter(exchange) // 无注解,直接放行

        // 允许访问的情况,直接放行
        if (authAnnotation.value == AuthType.ALLOW) {
            return chain.filter(exchange)
        }

        // 响应式方式获取用户、校验权限
        return getUserFromRequest(exchange.request)
            .flatMap { user ->
                if (isUserAuthorized(user, authAnnotation.value)) {
                    chain.filter(exchange)
                } else {
                    renderForbiddenResponse(exchange)
                }
            }
            // 捕获令牌错误、用户不存在等异常,统一返回403
            .onErrorResume { renderForbiddenResponse(exchange) }
    }

    // 从请求头解析令牌并查询用户(响应式实现)
    private fun getUserFromRequest(request: ServerHttpRequest): Mono<User> {
        val token = request.headers.getFirst("Authorization")?.removePrefix("Bearer ")
            ?: return Mono.error(IllegalArgumentException("Missing authorization token"))
        return userService.findUserByToken(token) // 替换成你的实际令牌解析逻辑
    }

    // 校验用户是否符合权限要求
    private fun isUserAuthorized(user: User, authType: AuthType): Boolean {
        return when (authType) {
            AuthType.ADMIN -> user.roles.contains("ADMIN")
            else -> true
        }
    }

    // 返回403禁止访问的响应
    private fun renderForbiddenResponse(exchange: ServerWebExchange): Mono<Void> {
        exchange.response.statusCode = HttpStatus.FORBIDDEN
        val errorBody = """{"code": 403, "message": "Access Denied"}"""
        return exchange.response.writeWith(
            Mono.just(exchange.response.bufferFactory().wrap(errorBody.toByteArray()))
        )
    }
}

3. 控制器用法完全不变

你的注解式控制器代码可以直接照搬,和Spring MVC里的写法完全一致:

@RestController
class DemoController {

    @GetMapping("/foo")
    @Auth(AuthType.ALLOW)
    fun doesntNeedAuth(): Mono<String> {
        return Mono.just("Hello, no auth required!")
    }

    @GetMapping("/bar")
    @Auth(AuthType.ADMIN)
    fun adminMethod(): Mono<String> {
        return Mono.just("Hello, admin user!")
    }
}

几个关键注意点

  • 响应式编程要求所有异步操作都用Mono/Flux包裹,不能像MVC那样同步返回布尔值,所以用户查询、错误处理都要遵循响应式规范
  • 获取HandlerMethod时,用HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE这个内置属性,是Spring WebFlux存储当前匹配处理器的标准键
  • 如果你的权限逻辑更复杂,也可以考虑用@PreAuthorize结合自定义方法安全表达式(需要开启@EnableReactiveMethodSecurity),但上面的WebFilter方式更贴合你原有代码的逻辑,迁移成本最低

内容的提问来源于stack exchange,提问作者NikichXP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:07:31