3

我一直在一个 web 项目中使用 noir,我想限制对用户的访问,这取决于他们对 defpage 宏定义的所有可能路由的访问级别(和子级别)。所以最初我有

(defpage [:post "/mysite"] {:as input}
  (if-not (has-reqd-user-level? :levelX :sublevelY "/grantedRoute")
    (noir.response/redirect "/insufficientRights")
    ...))

然后我认为这将摆脱样板代码:

(defmacro defpage-with-user-level [level sublevel granted-route route data expr]
  `(defpage ~route ~data
     (if-not (has-reqd-user-level? ~level ~sublevel ~granted-route)
       (noir.response/redirect "/insufficientRights")
       ~expr)))

最后,我们使用它如下:

(defpage-with-user-level :levelX :sublevelY "/grantedRoute"
  [:post "/mysite"] {:as input}
  (html
    [:body [:h1 (str "Hello " (:name input) "!")]]))

但是正如 Rich Hickey 的这篇文章所提到的,https: //groups.google.com/forum/#!msg/clojure/4II-HKr_Pu0/2IcKit99cagJ ,由于位置绑定,感觉有点尴尬,这不是惯用的当已经存在地图时。

但是,我一直在寻找一些关于在宏中使用解构绑定的示例或讨论,遗憾的是,我没有发现它们的任何明确用途,因为它一直在传递未计算的表达式。

因此,我想到了以下解决方案:

(defmacro defpage-with-user-level [dts expr]
  `(defpage (:route ~dts) (:data ~dts)
     (if-not (has-reqd-user-level? (:level ~dts) (:sublevel ~dts) (:granted-route ~dts))
       (noir.response/redirect "/insufficientRights")
       ~expr)))

但是现在,还不清楚如何将映射本地的数据映射从 :get 和 :post 传递到上面的示例中的本地。

我做对了,让我的第一次尝试不受干扰,还是我真的需要使用第二种方法?我希望不是。还有其他选择吗?请告诉我。

4

1 回答 1

4

你的第一个解决方案很好。Rich 所说的是使用普通的旧地图来传递数据,而不是为每种类型的数据创建新的类型/类。例如:您可以使用简单的地图来表示用户信息,而不是创建一个类来表示用户数据。

就您的第二次尝试而言,您可以在宏中使用地图解构:

(defmacro defpage-with-user-level [{:keys [route data level sublevel granted-route]} expr]
  `(defpage ~route ~data
     (if-not (has-reqd-user-level? ~level ~sublevel ~granted-route)
       (noir.response/redirect "/insufficientRights")
       ~expr)))

(defpage-with-user-level {:level :levelX 
                          :sublevel :sublevelY 
                          :granted-route "/grantedRoute"
                          :route [:post "/mysite"] 
                          :data {:as input}}
  (html
    [:body [:h1 (str "Hello " (:name input) "!")]]))
于 2013-03-16T08:29:32.883 回答