This post is part of the Web Application Development with Clojure tutorial. You might want to read the previous posts before this post for continuity’s sake.
- Part 1: Project Setup
- Part 2: Data model definition with Lobos and Korma
- Part 3: Loading Fixures with clj-yaml and HTML Templating with Enlive
- Part 4: Adding CSS, Post detail page and Simple Authentication
- Part 5: Blog Administration Area
Introduction
Over that past 4 parts you have seen how to start with creating a simple blog using Clojure, render the posts and finally how to add a simple login page that will check the username and password and redirect to “admin” page. In this part we’ll finish the administration area of the blog that will help us create new blog posts.
Source code on github
The code for this series is now available on github and the source code is tagged with part names. If you want to checkout the code for a specific part of this tutorial you can do so using the following command:
1 2 3 |
git clone git://github.com/vijaykiran/clog.git cd clog git checkout part5 |
Sessions
When a user logs into the “admin” area using our login form, we need to keep track of her session and allow them to perform administrative operations such as managing posts or setting their password etc. Ring library provides a simple session middleware that uses various session storage options – cookie, in-memory and database backed session stores. You can create your own session implementations by implementing the SessionStore protocol. For our application we’ll just use the cookie-store to store the session information.
First step in creating the session is using the wrap-session function. We’ll add this to our routes and make sure that the session is wrapped for all the starting with “/admin”. Update your routes definition in core.clj as follows:
1 2 3 4 5 6 7 8 9 10 |
;; Routes definition (def routes (app (wrap-file "resources/public") (wrap-params) (wrap-session {:cookie-name "clog-session" :store (cookie-store)}) ["login"] (delegate login) ["admin"] (delegate admin) [""] (delegate index) [id] (delegate post id))) |
Also make sure that you add the necessary namespaces to the core.clj namespace.
1 2 3 4 5 6 7 8 9 10 11 |
(ns clog.core (:use ring.adapter.jetty ring.middleware.resource ring.middleware.reload ring.util.response ring.middleware.file ring.middleware.params ring.middleware.session ring.middleware.session.cookie net.cgrand.moustache clog.controller)) |
When a user logs in, we can use the session to store the username, and in subsequent requests to admin pages, we’ll verify if the session contains the username otherwise we send the user back to login page. First let us update the login method in the controller to make sure that we set the “username” on the session cookie.
1 2 3 4 5 6 7 8 9 |
(defn login "Login Handler" [req] (let [params (:params req)] (if (empty? params) (response (login-page)) (if (= (get params "username") (get params "password")) (assoc (redirect "/admin") :session {:username (get params "username")}) (response (login-page "Invalid username or password")))))) |
When the username is valid according to our logic – we set the session map during redirect. This will set a cookie with the name “clog-session” when the user is logged in. You can check the cookie in your browser’s inspector.

Now we’ll tweak the admin handler to check whether the username is set on the session cookie, if not, we’ll redirect the user to the login page.
1 2 3 4 5 6 7 |
(defn admin "Admin handler" [req] (let [username (:username (:session req))] (if (nil? username) (redirect "/login") (response "Admin Page")))) |
The next step is to add a logout function that will clear the session to make sure the username key is removed from the session.
1 2 3 4 |
defn logout "Logout handler" [req] (assoc (redirect "/") :session nil)) |
We also need to update our routes to make sure that”/logout” works as expected. Just add the new logout handler to the routes in core.clj as follows:
1 2 3 4 5 6 7 8 9 10 |
(def routes (app (wrap-file "resources/public") (wrap-params) (wrap-session {:cookie-name "clog-session" :store (cookie-store)}) ["login"] (delegate login) ["logout"] (delegate logout) ["admin"] (delegate admin) [""] (delegate index) [id] (delegate post id))) |
After these changes, when you try to access “/admin” without logging in you’ll be redirected to the login page as expected. Browsing to “/logout” page will “clear” your session redirecting you back to the home page of the blog.
Since we are now having only one “secure” page, we just added the session check to the admin handler function itself. Clearly this isn’t a nice way, since in a production version of your blog, you might have many more admin pages such as user settings, post settings etc. This approach of verifying the session in every function look pretty stupid in that case.
You can move the session checking logic to a different security wrapper handler which will check the request before forwarding to the next handler. If this security wrapper handler sees that the url is one of the “secure” urls, it will verify the session. When the session doesn’t contain the username key, it can redirect to the login page.
Blog post admin page
Now we have our simple security in place, let us finish our blog posting function that will allow us to create a new post. First create the admin html page which contains the form for the blog post.
1 |
Clog - Admin<script src="/bootstrap/js/html5.js" type="text/javascript"></script> |
1 |
New Post
Great series Vijay. Thanks for taking the time to prepare it.
You’ve prompted me to look at Enlive, and while I’m interested in it, I’m enough of a Clojure newbie that I can’t get my mind around how you would use the same navigation, header, footer, etc around each of the different templates to avoid duplicating the markup in each html page. Is that something you could add to this installment?
Hi, thanks for the comment. You can have “templates” composition with enlive. Unfortunately it will be too much for this series, since I wanted to keep the parts small and simple.
But I’ll post more about my experiments with enlive soon – so keep an eye out :-)
This is really awesome series of the tutorials for understanding the entire process with ease. Thanks a tonne man for the series. Nothing could help me push my self to go for it without such a insightful help for you brother. Thanks Again
[…] Part 5: Blog Administration Area […]
Still waiting for part 6! :D
I’m sorry – swamped with other work now – the draft for the part 6 is almost ready. I hope to publish it before christmas :)
Vijay, thanks for this. I worked through all of it and it’s made some things that were opaque very clear.
@google-37493359364923d790c221a433e3c427:disqus Hi – I’m glad that you find this useful – are you the author of http://www.learningclojure.com/ ? if so – thanks for that :)