Building a blog with Grails - tutorial 5

Last time, during tutorial #4, be set up the necessary building blocks for the administrative section of our blog. We created a controller, the action and the necessary views to accommodate it. In addition, we secured it using a filter that forces a user ( who has not logged in ) back to the login view.

Tonight, we're going to expand on the work we have done so far by making passwords more secure, creating the login functionality and enhancing our administrative index view.

Cop your caffeine buzz and let's get started.

The first thing we need to do is modify our BootStrap.groovy file so that we can make our lone user's password more secure. We don't have to look far to find the functionality that will make this modification very easy. Fortunately, there's a library at our disposal and we're going to import it. Here's what our BootStrap.groovy file looks like now:

import org.apache.commons.codec.digest.DigestUtils as DU

class BootStrap {

     def init = { servletContext ->

        def blog = new Blog(
            name:'GroovyBlog',
            url:'http://www.groovyblog.com'
        ).save()

        def user = new User(
            username:'jimbo',
            password:DU.md5Hex('password'),
            confirmPassword:DU.md5Hex('password'),
            active: true,
            dispName:'jim',
            url:'http://www.boxedfool.com',
            email:'jim@home.com',
            status:'administrator',

        ).save()

        blog.addToUsers( user )

        def t1 = new Tag(name:'blog').save()
        def t2 = new Tag(name:'install').save()

        def k1 = new Keyword(name:'blog').save()
        def k2 = new Keyword(name:'install').save()

        def s1 = new Subject(name:'blog').save()
        def s2 = new Subject(name:'groovy').save()
        def s3 = new Subject(name:'software').save()

        def p = new Post(
            title:'I installed the GroovyBlog',
            body:'<p>I just installed the Groovy Blog and it works!!!</p>',
            extendedBody:'<p>Of course . . . how could I <b>possibly fail?</b></p>',
            slug:'i-installed-the-groovy_blog',
            views: 0,
            status: 'published',
            acceptComments: true,
            acceptTrackbacks: true,
            publishDate: new Date(),
            author: user
        )

        p.addToTags( t1 )
        p.addToTags( t2 )
        p.addToKeywords( k1 )
        p.addToKeywords( k2 )
        p.addToSubjects( s1 )
        p.addToSubjects( s2 )
        p.addToSubjects( s3 )

        p.save()

        user.addToPosts( p )
        user.save()

        blog.addToPosts( p )
        blog.save()


     }
     def destroy = {
     }
}


Notice that in the first line we import the DigestUtils class as DU to use for the purposes of hashing the user's password. Then, in the following lines we pass in the hashed version of the user's password:

password: DU.md5Hex('password'),
confirmPassword: DU.md5Hex('password'),


While this doesn't necessarily make a user's password un-crackable, it is certainly better than storing passwords in plain text.

The Form

With that done, we can concentrate on getting users logged in. We'll need two things to get that done: a login.gsp for the view and a login action in our AdminController.

Our login.gsp should look something like this:

<html>
    <head>
        <title>
            <g:if test="${blog}">${blog?.name}</g:if>
        </title>
        <meta name="layout" content="admin" />
    </head>
    <body>

        <div id="alpha">
            <h1>Login</h1>

            <g:form method="post" action="login">               

                <div class="form-row">
                    <label for="username">Username:</label>
                    <g:textField name="username" value="${user?.username}" />
                </div>

                <div class="form-row">
                    <label for="password">Password:</label>
                    <g:
passwordField name="password" value="" />
                </div>

                <div class="form-row">
                    <label for="">&nbsp;</label>
                    <g:submitButton name="login" value="Login!"/>                </div>

            </g:form>

        </div>

        <div id="beta">
            beta
        </div>

    </body>
</html>


In this file you will see a few, new tags. First off, notice that we are using the admin layout that we created in tutorial 4:

<meta name="layout" content="admin" />

Instead of using HTML form tag, we'll use Grails' built-in form tag:

<g:form method="post" action="login">

We need to supply the name of the action that will be called and the method is optional, but always good practice to specify.

Next are Grails' text and password field tags:

<g:textField name="username" value="${user?.username}" />
<g:passwordField name="password" value="" />


In the name field we supply the appropriate property for the domain class. Lastly, we'll use Grails' login tag to generate a submit button:

<g:submitButton name="update" value="Update" />

Both the name and value are required for the submitButton tag.

The Action

With that in place our login action within the AdminController will look like this:

def login = {
        if( request.post ) {
            def user
            if( params.username && params.password ){
                user = User.findByUsernameAndPassword(
                    params.username,DU.md5Hex(params.password) )
                if( user ) {
                    flash.message = 'Welcome Back!'
                    session.user = user
                    redirect(action:'index')
                }
                else {
                    flash.message = 'No one exists with those credentials!'
                    render(view:'login', model:[user:user])
                }
            }
            else {
                flash.message = 'No one exists with those credentials!'
                render(view:'login', model:['user':user])
            }
           
        }
    }


You might be wondering what all that does, well let's break it down.

The first thing we do is check to make sure the request for this action came from a POST as we're not interested in GET requests for this action. Next we defined a variable that will represent our user. Since all the parameters for the request are conveniently placed into a map named "params," we'll look there and make sure the user has included the username and password. We need to pass on some kind of message to the user to let them know that we can't find anything. Grails provides a map called "flash" where we can store things for the next request. We'll store our message there so that when login.gsp renders, it will render the message I have stored there and present it to the user. After the request has ended, it will dispose of that message.

A bit of a side note here: We'll have to edit our admin.gsp layout to render those messages, however. I'm doing mine in the layout because the ability to display these messages is something I will likely do frequently:

Also, you might notice that I did something extra. If no user is present we don't need to display the navigational bar. This way, the login.gsp view and the index.gsp view can share the same layout.

<div id="page">
            <div id="header">header</div>

            <g:if test="${session.user}">
                <div id="nav">
                    <ul class="left">
                        <li>Something</li>
                        <li>Something</li>
                        <li>Something</li>
                    </ul>
                    <ul class="right">
                        <li>Something</li>
                        <li>Something</li>
                        <li>Something</li>
                    </ul>
                </div>
            </g:if>

            <div id="content">

                <g:if test="${flash.message}">
                  <div class="message">${flash.message}</div>
                </g:if>

                <g:layoutBody />

            </div>
        </div>


If those two parameters do not exist we can't log in the user, so we render the login view. The user, even though it does not really exist yet, is passed on to the view.

In the event the username and password are present we use a dynamic finder method, findBy"UsernameAndPassword", to query the database for the user. Since we're using the username and password to find the user we'll need to supply the username and the hashed password. Notice that we are using the same import and method to hash the password as we did in our BootStrap.groovy file.

After we query the database, if our user exists we set a message welcoming the user, store the user in the session and redirect to our admin area index action. While we're at it, let's do something in the index action. I imagine it might be handy if on the primary page of the admin area we were able to see a list of posts that have been published. So, in our AdminController's index action let's use a database query to get all the posts we currently have in our database ( yep all one of them ):

def index = {
        def posts = Post.list()
        [posts:posts]
    }


This query is similiar to the one we did in our SiteController's index action. The primary difference is that we're not looking for any post in particular, we want all of them - just a list of all the posts in our database. Afterwards we use the variable we created to hold them as something to pass on to our index.gsp view to display them like so:

<html>
    <head>
        <title>
            <g:if test="${blog}">${blog?.name}</g:if>
        </title>
        <meta name="layout" content="admin" />
    </head>
    <body>

        <div id="alpha">
            <h1>Admin</h1>
            <g:if test="${posts}">
                <table border="1">
                    <tr>
                        <th>Title</th>
                        <th>Author</th>
                        <th>Publish Date</th>
                    </tr>
                    <g:each in="${posts}">
                        <tr>
                            <td>${it.title}</td>
                            <td>${it.author.username}</td>
                            <td>${it.publishDate}</td>
                        </tr>
                    </g:each>
                </table>
            </g:if>
        </div>

        <div id="beta">
            beta
        </div>

    </body>
</html>


Notice that I check to see if the "posts" variable exists and then display them using the each tag outputting the title, the author's username and the publish date of the post. I suppose I could have gottone all Web 2.0-ish and such by using divs, but I decided to use a table as this is tabular data, imho.

How's it all working?

Let;s start up our app and see if things are working the way we'd like them to when browsing to http://localhost:8080/GroovyBlog/admin/. The first thing we should see is that the login view is displayed as it should:



While it's tempting to put the right username and password in, let's try not putting any in. The logic in our action should send the user back to the login view and provide a message for them:



With that out of the way, go ahead and provide the wrong username and password. You should get the same screen again. After we've tried that, go ahead and put in the appropriate credentials. After doing so, we should be allowed to our administrative index action and shown the index.gsp view:



Things are going pretty well if you can see the above page.

That's the end of today's tutorial. By the end of the next tutorial we will be adding posts via the administrative area.

You're more than welcome to provide any feedback, ask questions, whatever in the comments or move right along to the next tutorial in this series.
OpenID accepted here Learn more about OpenID

About this Entry

This page contains a single entry by Jim published on April 12, 2009 12:45 PM.

Building a blog with Grails - tutorial 4 was the previous entry in this blog.

Building a blog with Grails - a brief pause is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.