Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Going Live with a Grails-Powered Blog : Page 2

Once you have built a Grails project, how do you deploy it? Learn how to use Groovy builders, filters, and tags to deliver a Grails project. Along the way you'll delve into AJAX and deploy a Grails application in Tomcat.


advertisement
Securing The Blog
You need to add some authentication to the blog so only you can make and edit posts. You will use a filter to secure certain actions and a tag to hide features that should be available only to authenticated users. On a larger project, integrating with a security framework like Acegi Security would be more appropriate for authentication, but this approach allows you to see how trivial implementing filters and tags are in Grails.

The filter code is a Groovy class that must exist in the grails-app\conf directory. Grails will pick up all classes that end in "Filters" in the conf directory as containing filter definitions. The filter class must have a closure defined called "filters." Each node within this closure defines a filter.

You can see from the UserFilters class in the following listing that an "authenticated" filter has been declared:



class UserFilters { def filters = { authenticated(controller: "post", action: "edit") { before = { if (!session.user) { redirect(controller: "user", action: "login") return false } } } } }

The arguments that are passed to the filter determine the scope of the filter (i.e., which actions and controllers the filter is executed for). In the application, you have only one action that needs to be secured: the edit post action. You can declare the scope of the filter by controller and action, or by URI. To force a user to log in when adding a comment to a post, you would define all actions on the comment controller as being secure:

authenticated(controller: "comment," action: "*") {...}

Alternatively, you could control this access via the URI:

authenticated(uri: "/comment/**") {...}

The closure definition in the UserFilters class tells Grails to execute the filter before the action is performed. You could also have defined the filter to execute after the action is performed or "afterView," which would execute the filter when the view had been rendered.

A simple check determines whether there is a user attribute in the session. If not, the user is redirected to the login page. Returning false in the filter informs Grails that the requested action should not be executed.

At this point, a Java web developer who isn't familiar with Grails might have a few questions:

  1. Where did the session come from?
  2. Since when has there been a user property on the HTTPServletSession interface?
  3. Should a user property really return true?

These are all valid concerns with simple answers:

  1. Grails exposes a number of objects to the filter for convenience, including the session object.
  2. Grails also dynamically adds some convenience conventions to the HTTPServletSession interface to allow session attributes to be accessed as if they were properties on the session object.
  3. A Boolean comparison in Groovy doesn't just check if something is true or false, but also if it is null, zero, or some other form of false (depending on the object being compared). In this instance, if the user is not in the session then the property will return null and equal false for the if statement.

Testing the Security
Create a new controller called UserController with this code under the grails-app\views\user directory:

class UserController { def login = { render(view: "login") } }

The UserController will render the login page when authentication is required. In the same grails-app\views\user directory, create a new login.gsp with this code:

<%@ page contentType="text/html;charset=UTF-8" %> <html> <head><title>Login</title></head> <body> <g:form action="authenticate" method="post"> <dl> <dt>Username:</dt> <dd><g:textField name="username"/></dd> <dt>Password:</dt> <dd><input type="password" name="password"/></dd> </dl> <g:submitButton name="login" value="Login"/> </g:form> </body> </html>

The login page will ask the user to enter his or her username and password. You are now ready to run the application (grails run-app) and test whether the edit post action is secure.

When the application is running, if you go to the post list page (http://localhost:8080/groovypublish/post) and then try to click on the "Create a new post" or "Edit this post" links, you will be taken to the login page (see Figure 1).

Figure 1. Login Required: A login page is displayed if a user tries to create a new post or edit a post.

Now Let Me In!
Now that you have secured the application, you need to be able to authenticate a valid user so you can get in and write posts.

The first thing you need is a User domain object to store the authentication details of a blog user (see Listing 4). This class is created in the domain directory along with the other domain objects. The only new feature here is the addition of the unique constraint on the username field. This checks if the username is unique in the database when validation is performed.

The next task is to update the UserController to have an authenticate action. There are two interesting aspects to this code: the introduction of the UserService and the use of the flash scope through the flash property.

In Grails, a service is convention in the same way that domain objects and controllers are conventions. If a UserService Groovy class exists in the grails-app\services directory, then it becomes a Grails service. Services contain business logic that can be reused by other classes. By defining a property in the controller with the same name as the service class, Grails uses Spring to automatically inject an instance of the service into the controller (more on the implementation of the service later).

Grails also introduces a new scope to Java web development. To the currently available request scope and session scope, Grails adds something called flash scope (an idea taken from the Ruby on Rails framework). The lifespan of flash scope begins while one user request is being serviced and ends when the following user request has finished executing. It is commonly used (as in this blog example) to pass data to a request that will be performed as a redirect without having to add the data to the query string of the redirect. In the authenticate action example in the previous section, for example, if the authentication fails:

  1. A message will be put in flash scope.
  2. A redirect will be sent back to the client's browser.
  3. The message will be available in flash scope to be rendered when the login page is requested.

The final step is to perform the authentication, which the authenticate method on the user service does by returning the result of a search for users with the given username and password. The interesting thing here is the use of the Grails Object Relational Mapping (GORM) dynamic finders. Internally, Grails builds up a Hibernate query based on the properties that are specified in the name of the find method. To further illustrate this, the eventual SQL that would be executed by this dynamic finder may look something like this:

select * from user where username = ? and password = ?

It is also possible to add suffixes to the properties that perform comparison operations other than equals:

def post = Post.findByTitleLike("%grails%") def comment = Comment.findByDateCreatedGreaterThan(yesterday)

See the online Grails documentation for a full set of the comparison suffixes that can be used for dynamic finders.

The final step before you can log in is to create a user in the BootStrap class:

new User(username:"me", password:"password", firstName:"A", lastName:"Developer").save()

Now if you go back to the application you should be able to log in with username "me" and the password "password." There is also a logout action on the controller in UserController, so you can put a link like the following on the post list page to logout from the application:

<g:link controller="user" action="logout"> Logout </g:link>

You will see how to make the logout link available on all pages later.

You Can't Do That
To finish off this basic security mechanism, you need to be able to hide the links that require authentication from unauthenticated users. You could do this by wrapping each link with an "if" statement or a tag that checks the session, or you can write your own tag that will handle this automatically.

The convention for tag libraries is that they must exist in a class that ends with TagLib and exists in the grails-app\taglib directory. The static namespace property determines the namespace that will be used to access the tags from a GSP, from other tags, or from controllers. To define a tag, you create a closure that takes a map of attributes and the body of the tag:

public class SecureTagLib { static namespace = "gp" def secureLink = { attrs, body -> if(session.user) { out << g.link(attrs, body) } } }

Figure 2. An Unauthenticated User View: Users that have not been authenticated should not see the links to create a new post and edit a post.

The secure link tag checks if a user is in the session and, if so, passes on its arguments to the Grails link tag that you would normally use. The link tag can either be called directly or through the g namespace property. (The g namespace property is used for clarity in case another link tag is created in a separate namespace in the future.)

Everything in Groovy is an object, even operators. This allows operators to be overridden. The << (left shift) operator has been overridden in Groovy to mean "append to" for objects such as StringBuffers, Writers, Lists, Files, and Sockets. This tag can now be used in a GroovyServer Page (GSP) to hide links that should not be accessible to unauthenticated users (see Figure 2).

To allow authenticated users to be able to create and edit posts (see Figure 3), replace this code:

<g:link controller="post" action="edit"> Create a new post </g:link>

Figure 3. An Authenticated User View: Authenticated users should be able to create and edit posts.

With this code:

<gp:secureLink controller="post" action="edit"> Create a new post </gp:secureLink>

And this code:

<g:link controller="post" action="edit" id="${post.id}"> Edit this post </g:link>

With this code:

<gp:secureLink controller="post" action="edit" id="${post.id}"> Edit this post </gp:secureLink>



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap