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.