Avenue is small set of macros for web apps that use Compojure. Primarily, it provides a simple mechanism for authorization.
Add the following dependency to your project.clj
file:
[com.hendrick/avenue "0.1.0"]
In a web app, most requests fall into one of a few categories. You have pages...
(page
"/admin/user-permissions"
[:user.role/superAdmin]
user-permissions-view/show)
You've got Ajax requests...
(xhr
POST "/admin/update-account"
[:user.role/superAdmin]
actions/update-account)
And you might have some form posts...
(form-post
"/admin/create-account"
[:user.role/superAdmin]
actions/create-account)
All Avenue does is provide a little shorthand for these common cases. You can mix and match Avenue-style routes with regular Compojure routes.
Each of the page
, xhr
, and form-post
macros require the same arguments,
with the exception that for xhr
calls, you must specify the request's HTTP
method.
A call looks like this
(page|xhr|form-post
http-method ;; xhr only
url
auth-data
actions) ;; variable
The http-method and url arguments are just forwarded to Compojure/ring. auth-data
is
any data structure that identifies who is allowed to access this route. The
contents of auth-data
are not used by Avenue. Avenue will pass the contents
of auth-data
to your :auth-fn
For example, you might have several routes that are only accessible by admin users, you can indicate this with a keyword.
(page
"/admin/do-secret-stuff"
:adminOnly
view/show-secret-page)
You might have some other routes that are accessible to everyone.
(page
"/welcome"
:allowEveryone
view/welcome-page)
The keywords you choose are actually opaque to avenue, you specify their meaning in an :auth-fn
.
(defn -main [& {:as args}]
(let [app (-> routes
(av/wrap-auth {:auth-fn (fn [auth-data req]
(condp = auth-data
:allowEveryone true
:adminOnly (:is-admin (db/find-user (:user-id (:session req))))
false))
:authorized-page-fn show-page
:unauthorized-page-fn redirect-to-welcome-page})
(handler/site {:session {:store (cookie/cookie-store {:key "this is a secret"})}}))]
(web/run app args)))
If you find keywords aren't sufficient to express your auth requirements, you
can use any arbitrarily complex Clojure data structure. It's up to you to find
the :auth-fn
and route data-structure that best suits your needs.
For a working example, check out the sample app.
To use Avenue, you must include av/wrap-auth
in your middleware stack. It takes
a few options:
:auth-fn
is a function that returns a truthy or falsey value indicating
whether a user is allowed access. As parameters, we'll pass the data
structure that's specified along with the route, and the request itself.
The data structure that gets passed to the auth-fn is exactly what's specified
in the route definition. It is the second argument of the page
or form-post
macro, and the third argument of the xhr
macro. Avenue does nothing with this
data except to pass it to the auth-fn.
:authorized-page-fn
is a function that the page
macro will call with the
result of the route's actions. It's ignored by the xhr
and form-post
macros.
:unauthorized-page-fn
is a function that any macro will call when the
:auth-fn
returns a falsey value.
If you don't care much about auth, you can omit :auth-fn
and
:unauthorized-page-fn
from the configuration that's passed to
av/wrap-auth
, and also drop the auth data structures from your routes.
Copyright 2015 Hendrick Automotive Group
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.