Web Application Development with Clojure – Part 5

By vijay on February 27, 2012 — 6 mins read

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.


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:


You can read more about ring’s session and cookie store here and here

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:

Also make sure that you add the necessary namespaces to the core.clj namespace.

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.

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.

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.

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:

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.



New Post



Posted in: Programming

Leave a comment

Leave a Reply to VijayKiran.com – Web Application Development with Clojure – Part 1 Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.