如何在Suave应用中拦截未授权IP请求并返回403停止路由
解决Suave中未授权IP直接返回403的问题
嘿,完全懂你的需求——你要的不是“跳过当前路由继续找下一个”,而是直接终止请求处理,立刻返回403状态码对吧?Suave里确实有简洁的方式实现这个,不需要复杂的分支组合器,自定义一个中间件风格的WebPart就能搞定。
步骤1:定义授权IP列表和IP获取逻辑
首先,先把你的授权IP存成一个集合(方便快速查找),再写个函数从请求上下文里拿到客户端IP:
open Suave open Suave.Http open Suave.Http.Successful open Suave.Http.Writers open System.Collections.Generic // 你的授权IP列表 let allowedIps = Set ["127.0.0.1"; "192.168.1.100"] // 获取客户端IP(如果部署在反向代理后,记得从X-Forwarded-For头取) let getClientIp (ctx: HttpContext) = match ctx.request.headers with | Some headers when headers.ContainsKey "X-Forwarded-For" -> headers.["X-Forwarded-For"].Split(',') |> Array.head |> fun s -> s.Trim() | _ -> ctx.request.clientIpAddress.ToString()
步骤2:编写IP授权组合器
接下来写一个核心的WebPart组合器,它会先检查IP是否在授权列表里:
- 如果在,就把请求传递给后续的路由处理
- 如果不在,直接返回403响应,终止处理流程
let ipAuthorization (next: WebPart) : WebPart = fun ctx -> let clientIp = getClientIp ctx if allowedIps.Contains clientIp then // IP合法,继续处理后续路由 next ctx else // IP不合法,直接返回403 OK "Forbidden" |> withStatusCode 403 |> fun response -> response ctx
步骤3:把组合器应用到你的路由上
最后,把这个授权组合器放在整个路由树的最前面,这样所有请求都会先经过IP检查:
let app = ipAuthorization >=> choose [ path "/api/secure" >=> OK "This is secure content" path "/" >=> OK "Welcome to home page" // 其他路由... ]
为什么之前的过滤器不行?
你之前用的过滤器应该是filter组合器吧?它的逻辑是“条件满足就处理,不满足就跳过当前WebPart,继续找下一个路由”——这就是为什么它只是中断了当前路由搜索,却没有返回403。而我们上面写的组合器是主动返回了一个响应,直接终止了整个请求处理流程,完全符合你的需求。
如果想更简洁,也可以用choose直接把IP检查作为第一个分支:
let checkUnauthorizedIp = fun ctx -> let clientIp = getClientIp ctx if not (allowedIps.Contains clientIp) then Some (OK "Forbidden" |> withStatusCode 403) else None let app = choose [ checkUnauthorizedIp path "/api/secure" >=> OK "Secure content" path "/" >=> OK "Home" ]
这种方式下,choose会先执行checkUnauthorizedIp,如果返回Some response就直接返回,否则继续处理后面的路由。
内容的提问来源于stack exchange,提问作者team-rf
相关产品推荐
相关产品推荐

