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

Ring应用中如何认证部分路由并让公共路由免认证?

嘿,这个问题在Compojure开发里挺常见的,其实有几种很直观的解决方式,刚好能满足你把公共路由排除在认证中间件外的需求,我给你拆解一下:

核心思路:拆分路由+选择性应用中间件

因为defroutes确实会返回Ring处理器,所以我们可以把公共路由和私有路由分开定义,只给私有路由套上wrap-must-be-authenticated中间件,最后再把两个处理器合并起来就行。

方法一:分开定义后合并处理器

先单独定义无需认证的公共路由:

(defroutes public-routes
  (GET "/" [] "欢迎访问首页(无需登录)")
  (GET "/login" [] "登录页面")
  (GET "/about" [] "关于我们"))

再定义需要认证的私有路由,之后给它套上你的认证中间件:

(defroutes private-routes
  (GET "/dashboard" [] "用户专属仪表盘")
  (GET "/profile" [] "个人资料管理")
  (POST "/settings" [] "修改账户设置"))

; 给私有路由应用认证中间件
(def authenticated-private-routes
  (wrap-must-be-authenticated private-routes))

最后用Compojure的routes函数把两个处理器合并成最终的应用:

(def app
  (routes public-routes authenticated-private-routes))

这样Compojure会按顺序匹配路由,先检查公共路由,匹配不到才会走带认证的私有路由,完美避开公共路由被中间件拦截。

方法二:用wrap-routes直接在合并时指定中间件

如果你觉得分开定义中间件变量有点繁琐,也可以用Compojure提供的wrap-routes函数,直接在合并路由时给私有路由套中间件,写法更紧凑:

(def app
  (routes
    public-routes
    (wrap-routes private-routes wrap-must-be-authenticated)))

这个效果和方法一完全一致,只是写法更简洁。

额外提示:全局中间件的处理

如果你还有一些全局生效的中间件(比如wrap-params、wrap-keyword-params这类解析请求参数的中间件),可以把它们套在最外层,这样所有路由都会受到它们的处理:

(def app
  (-> (routes public-routes authenticated-private-routes)
      wrap-keyword-params
      wrap-params
      wrap-json-response))

最后提一句,如果你当前的认证中间件是直接抛异常,建议改成返回重定向到登录页或者401响应,这样用户体验会更友好哦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:55:11