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
相关产品推荐
相关产品推荐

