如何让Spring Cloud Gateway自定义过滤器返回401/403而非500?
解决Spring Gateway过滤器返回401/403而非500的问题
在Spring Gateway中,直接抛出IllegalStateException会被框架判定为内部服务器错误,返回500状态码。要返回符合语义的401或403,你需要主动构建错误响应并终止过滤器链,而非依赖未捕获异常的默认处理逻辑。
以下是修改后的完整代码(同时修正了原代码中先移除Authorization再读取的逻辑错误):
class AuthHeadersFilter( private val objectMapper: ObjectMapper ) : AbstractGatewayFilterFactory<AuthHeadersFilter.Config>() { override fun apply(config: Config?): GatewayFilter { return GatewayFilter { exchange, chain -> val httpHeaders = exchange.request.headers // 先读取Authorization header,再执行移除操作 val authHeader = httpHeaders[AUTHORIZATION]?.firstOrNull() ?: return@GatewayFilter buildErrorResponse(exchange, HttpStatus.UNAUTHORIZED, "Authorization header is missing") // 解析JWT Claims,捕获解析异常返回401 val jwtClaims = try { jwtClaims(authHeader) } catch (e: Exception) { return@GatewayFilter buildErrorResponse(exchange, HttpStatus.UNAUTHORIZED, "Invalid Authorization token") } // 检查authz声明是否存在,缺失则返回403 val authzClaim = jwtClaims.getStringClaimValue("authz") ?: return@GatewayFilter buildErrorResponse(exchange, HttpStatus.FORBIDDEN, "Authz claim is missing") // 解析权限列表,格式错误则返回403 val permissions: List<Permissions> = try { objectMapper.readValue(authzClaim) } catch (e: Exception) { return@GatewayFilter buildErrorResponse(exchange, HttpStatus.FORBIDDEN, "Invalid Authz claim format") } // 构造修改后的请求,移除Authorization并添加X-OrgId val modifiedRequest = exchange.request.mutate() .headers { headers -> headers.remove(AUTHORIZATION) permissions.forEach { headers.add("X-OrgId", it.scope.org) } }.build() // 继续执行后续过滤器链 chain.filter(exchange.mutate().request(modifiedRequest).build()) } } // 封装错误响应构建逻辑,返回JSON格式错误信息 private fun buildErrorResponse(exchange: ServerWebExchange, status: HttpStatus, message: String): Mono<Void> { val response = exchange.response response.statusCode = status response.headers.contentType = MediaType.APPLICATION_JSON val errorBody = objectMapper.writeValueAsString(mapOf("error" to message)) val buffer = response.bufferFactory().wrap(errorBody.toByteArray()) return response.writeWith(Mono.just(buffer)) } class Config // 保持原配置类定义不变 }
核心修改说明:
- 替换异常抛出逻辑:将原本的
throw IllegalStateException改为调用buildErrorResponse,直接生成指定状态码的响应。 - 终止过滤器链:通过
return@GatewayFilter返回Mono<Void>,告知Spring Gateway不再执行后续的过滤器和路由逻辑。 - 状态码语义区分:
- 当Authorization header缺失或Token解析失败时,返回401 Unauthorized(身份验证失败)。
- 当authz声明缺失或格式错误时,返回403 Forbidden(身份验证通过但无权限)。
- 修正原代码逻辑bug:调整了Authorization header的读取和移除顺序,避免先移除后读取导致的空值问题。
内容的提问来源于stack exchange,提问作者Rustam Issabekov
相关产品推荐
相关产品推荐

