Invoke the SpringSource Tool Suite and make sure the Grails perspective is active. Create a new grails project and name it BCSBookStore.
Invoke the Grails command prompt and issue the following command
install-plugin spring-security-core This action installed the spring security core. Now we are ready to invoke the quick start by issuing the following command
s2-quickstart com.bcsbooks User Role Three new domains were created in com.bcsbooks. [codesyntax lang="php"]package com.bcsbooks class Role { String authority static mapping = { cache true } static constraints = { authority blank: false, unique: true } }[/codesyntax][codesyntax lang="php"]package com.bcsbooks class User { String username String password boolean enabled boolean accountExpired boolean accountLocked boolean passwordExpired static constraints = { username blank: false, unique: true password blank: false } static mapping = { password column: '`password`' } Set<Role> getAuthorities() { UserRole.findAllByUser(this).collect { it.role } as Set } }[/codesyntax][codesyntax lang="php"]package com.bcsbooks import org.apache.commons.lang.builder.HashCodeBuilder class UserRole implements Serializable { User user Role role boolean equals(other) { if (!(other instanceof UserRole)) { return false } other.user?.id == user?.id && other.role?.id == role?.id } int hashCode() { def builder = new HashCodeBuilder() if (user) builder.append(user.id) if (role) builder.append(role.id) builder.toHashCode() } static UserRole get(long userId, long roleId) { find 'from UserRole where user.id=:userId and role.id=:roleId', [userId: userId, roleId: roleId] } static UserRole create(User user, Role role, boolean flush = false) { new UserRole(user: user, role: role).save(flush: flush, insert: true) } static boolean remove(User user, Role role, boolean flush = false) { UserRole instance = UserRole.findByUserAndRole(user, role) instance ? instance.delete(flush: flush) : false } static void removeAll(User user) { executeUpdate 'DELETE FROM UserRole WHERE user=:user', [user: user] } static void removeAll(Role role) { executeUpdate 'DELETE FROM UserRole WHERE role=:role', [role: role] } static mapping = { id composite: ['role', 'user'] version false } }[/codesyntax] It also creates some UI controllers and GSPs:
grails-app/controllers/LoginController.groovy
grails-app/controllers/LogoutController.groovy
grails-app/views/auth.gsp
-
grails-app/views/denied.gsp
The script has edited
grails-app/conf/Config.groovy
and added the configuration for your domain classes. Make sure that the changes are correct.Create a controller that will be restricted by role.
create-controller com.bcsbooks.Secure
[codesyntax lang=”php”]
package com.bcsbooks class SecureController { def index = { } }
[/codesyntax]
Modify the controller so it produces output.
[codesyntax lang=”php”]
package com.bcsbooks class SecureController { def index = { render 'Secure access only' } }
[/codesyntax]
Start the server
runn-app
Before you secure the page, navigate to http://localhost:8080/bookstore/secure to verify that you can see the page without being logged in.
Shut down the app (using CTRL-C) and edit grails-app/conf/BootStrap.groovy to add the security objects that you need.
[codesyntax lang=”php”]
Shut down the app (using CTRL-C) and edit grails-app/conf/BootStrap.groovy to add the security objects that you need.
[codesyntax lang=”php”]
import com.bcsbooks.Role import com.bcsbooks.User import com.bcsbooks.UserRole class BootStrap { def springSecurityService def init = { servletContext -> def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush: true) def userRole = new Role(authority: 'ROLE_USER').save(flush: true) String password = springSecurityService.encodePassword('password') def testUser = new User(username: 'me', enabled: true, password: password) testUser.save(flush: true) UserRole.create testUser, adminRole, true assert User.count() == 1 assert Role.count() == 2 assert UserRole.count() == 1 } }
[/codesyntax]
Some things to note about the preceding BootStrap.groovy
:
springSecurityService
is used to encrypt the password.- The example does not use a traditional GORM many-to-many mapping for the User<->Role relationship; instead you are mapping the join table with the
UserRole
class. This performance optimization helps significantly when many users have one or more common roles.
We explicitly flushed the creates because BootStrap
does not run in a transaction or OpenSessionInView.
Mr. Arch Brooks, Software Engineer, Brooks Computing Systems authored this article.