Hi folks,

While it's not directly to your point, here is a pretty complete (IMHO) 
repository that I put together for getting you going with a new 
Clojure+Clojurescript website:

    https://gitlab.com/lambdatronic/clojure-webapp-template

Just clone it and check out the README.md file for a description of the 
build and runtime software requirements, build aliases, and expected usage 
in development and production modes. All of the build config files are 
built around the tools.deps clojure command-line interface and use a modern 
version of figwheel for development.

The deps.edn file contains aliases to:

1. Initialize a Postgresql database, including custom Clojure code that 
provides a simple "namespace"-like dependency system for your SQL files 
using a topo-sort procedure for dependency resolution. If you prefer to use 
a different database, you could easily tweak build_db.clj and create_db.sql 
to meet your needs.

2. Compile your CLJS code into app.js using advanced compilation settings 
(for production deployment).

3. Compile your CLJ code and launch an embedded Jetty web server on a port 
that you specify (or 8080 by default).

4. Launch Figwheel, compile your CLJS code into app.js using {optimizations 
:none} (for rapid development), launch an embedded Jetty web server on port 
8080, and automatically hotload any live changes to your CLJS files into 
your browser session and live changes to CLJ files into your server 
(available on browser refresh).

In addition, the Clojure code provides a pre-configured middleware stack 
with custom middlewares for request and response logging, exception 
handling, and parsing EDN params in the request object. There is also 
simple routing-handler function using plain old Clojure with some helper 
function to render HTML and EDN/JSON responses that you can extend or 
replace to meet your objectives.

Super-cool features include a pre-configured system of routes, CLJ 
handlers, and asynchronous CLJS functions (using core.async) that allow you 
to trivially call SQL functions directly from Clojure (synchronously) and 
to call both CLJ and SQL functions from Clojurescript (asynchronously) 
using a similar calling syntax. All database interaction is done through 
Sean Corfield's excellent next.jdbc library.

In my usual programming model, I encode any operations that should happen 
in the database as SQL functions in Postgresql. These are loaded by my 
`clojure -A:build-db only-functions` alias. Then from Clojure, I can call 
these SQL functions like so:

```clojure
(call-sql "contact.get_user" user-id)

;;=> [{:name "Rich Hickey" :residence "Hammock"}]
```

Alternatively, I can call the same function from Clojurescript like so:

```clojure
(def my-contact (atom nil))

(go
  (reset! my-contact (<! (call-sql-async! "contact.get_user" user-id))))

;; At which point @my-contact now evaluates to:
;;=> [{:name "Rich Hickey" :residence "Hammock"}]
```

You can do the same thing with CLJ functions from CLJS like so:

```clojure
(def cool-result (atom nil))

(go
  (reset! cool-result (<! (call-clj-async! "my-cool-clojure-function" 1 2 
3))))

;; At which point @cool-result now evaluates to whatever the result of 
calling (my-cool-clojure-function 1 2 3) on the webserver evalutes to.
```

NOTE: For security, only CLJ functions that are explicitly listed in 
remote_api.clj are allowed to respond to `call-clj-async!` requests from 
the browser.


Another pretty useful feature is a simple set of CLJS functions for storing 
arbitrary Clojure associative data (i.e. maps) in your browser's session 
storage:

- get-session-storage
- set-session-storage
- remove-session-storage
- clear-session-storage

The back-end code also includes a very simple `send-email` function 
implemented using `com.draines/postal` and a straightforward set of 
synchronously logging utility functions called `log` and `log-str` built 
using Clojure agents since using `println` and friends for back-end logging 
on a concurrent webserver is a recipe for unreadable spaghetti logs.

The front-end code is just a sparse skeleton using Reagent that provides a 
largely blank home page and an unstyled not found page. You can copy either 
page and use it as a template for adding any additional pages to your site. 
Note that the exported `init` method on each CLJS page receives the HTTP 
request params in JSON encoding as their first argument, so that you can 
easily respond to request parameters from the browser side of your 
application if you choose.

And last but not least, I've included a .dir-locals.el file in the toplevel 
of the repo that automatically configures your Emacs CIDER installation to 
seamlessly use the same figwheel settings as calling `clojure -A:figwheel` 
does. Magic!


Alright, folks. That's it from me for now. I hope some of you find this 
repository useful in your Clojure+Clojurescript web programming adventures.

Happy hacking!
  Gary

P.S. Specifically to your authentication point: The most straightforward 
and general place to implement authentication is in your middleware stack 
(handler.clj). Look for an existing Clojure library that provides an 
authentication middleware and add it at the level in the stack that you 
feel is most appropriate for your application. There are several of them 
out there.

Or...you could just be a maverick and roll your own. The fundamental 
operation of this middleware function is to grab some information from the 
request object and apply a strong test to it to determine if the next 
handler in the stack should be called or if an error response map should be 
returned. That's basically it. You can decide how best to design that 
authentication challenge based on your application's needs. Use encrypted 
passwords in your database, temporary user/session tokens, OAuth tokens, 
LDAP requests, or whatever else seems appropriate. If the test passes, call 
the next step handler from your authentication middleware. If it fails, 
return some kind of error response map with a meaningful status code (e.g., 
403 Forbidden).

Another very useful option (which may be combined with middleware-level 
authentication) is to perform more find-grained route-level authentication 
at the level of the routing-handler function (handler.clj). Maybe your 
authentication middleware could attach a :role or :permission-level 
attribute to the request map before calling the next-step handler. Then in 
your routing-handler, you can check that attribute to determine if the 
authenticated user should be granted access to a particular route. If not, 
just return an error response map from your routing-handler function (again 
with something like a 403 Forbidden status code).

These are general suggestions for how to approach the authentication and 
authorization process within a Clojure web app. Other developers may (and 
probably do) have their own opinions on how to do it. As always, YMMV.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/1954346f-ed06-4b66-a6d3-3d7ac5a4db87%40googlegroups.com.

Reply via email to