Fork me on GitHub
#duct
<
2020-02-04
>
kelveden16:02:13

Is there a way of annotating ataraxy routes in such a way as to make those annotations available to duct middleware? (As it'd only make sense doing this after ataraxy has routed, the middleware would have to be assigned individual routes too rather than :duct.handler/root.) Specifically, I'm trying to think of a way to create a generic bit of authorization middleware: the middleware will compare the permissions required for the route against those assigned to the user (available on the incoming request map) and (un)authorize as appropriate. So, I want to annotate each route in the duct config with the permissions required to access it - but in such a way as the authorization middleware can see them. The closest I can think of is if each permission were itself a piece of authorization middleware - that way each route could get assigned a middleware based on the permission required. But config would very quickly get cluttered up with middleware definitions as the API grew.

weavejester16:02:58

You can use metadata to assign middleware to a particular route, and this could be used to determine authorisation. For example:

{"/admin"
 ^{:roles #{"admin" "mods"}}
 {"/foo" [:foo]
  "/bar" [:bar]}}

weavejester16:02:53

So typically I’d have an single outer authentication middleware that determines the user ID and roles, and adds them to the request map, and then a bunch of inner authorisation middleware that checks to see if the user has a particular role, and forbids them from the resource if they don’t.

kelveden16:02:42

An outer authentication middleware is exactly what I've got actually - it's the inner middleware I'm struggling with. How is that metadata you've added exposed to the inner middleware?

weavejester16:02:20

It’s passed as an argument to the :roles middleware.

kelveden16:02:49

Ah... Thanks. I'll give that a go.

weavejester16:02:31

So:

{:routes     {"/foo" ^{:roles #{:admin}} [:foo]}
    :handlers   {:foo foo}
    :middleware {:roles wrap-roles}}

weavejester16:02:03

That calls the middleware (wrap-roles foo #{:admin})

kelveden16:02:43

Yeah that does the trick. The key thing I was missing was that I could pass that metadata as a second argument to the middleware. Thanks!