Last updated by admin 5 years ago

JSecurity Plugin - Quick Start Guide

This guide will quickly get you up and running with a standard setup for your web application's authentication and authorisation needs. Note that JSecurity is more flexible than described in this example, so please do visit the reference documentation later.

Installation

  1. First install the plugin into your project: {{grails install-plugin jsecurity}}
  2. Then, run {{grails create-db-realm}}.

Securing your web application

The controllers

The plugin applies access control settings to individual controllers, so that is where we will start. First, if you want to secure a particular controller, it must extend {{JsecAuthBase}} like so:

code: null
class MyController extends JsecAuthBase { … }
code: null
Next, you need to specify which actions require which roles and/or permissions. To do this, simply add a static property called {{accessControl}} and initialise it with a closure:
code: null
class MyController extends JsecAuthBase { static accessControl = { // All actions require the 'Observer' role. role(name: 'Observer')

// The 'edit' action requires the 'Administrator' role. role(name: 'Administrator', action: 'edit')

// Alternatively, several actions can be specified. role(name: 'Administrator', only: 'create', 'edit', 'save', 'update' (+)) }

… }

code: null
The above example only shows roles, but you can also restrict actions to particular permissions. To do this, you first have to create some permissions that implement the {{org.jsecurity.authz.Permission}} interface. Fortunately, there is an abstract class that you can extend that takes care of most of the implementation requirements:
code: null
import org.jsecurity.authz.AbstractPermission

class BasicPermission extends AbstractPermission { private static allowedActions = Collections.unmodifiableSet( 'view', 'create', 'modify', 'delete' (+) as Set)

// The constructor for a permission should have two parameters, for the target and actions. // If only one parameter is provided, it should be the string for the target, since this expected // by JsecDbRealm.findConstructor BasicPermission(String target, String actions) { super(target, actions) }

BasicPermission(String target, List actions) { super(target, actions as Set) }

Set getPossibleActions() { return allowedActions } }

code: null
Note that the first constructor, the one that takes two string arguments, is required. The other one is optional, but can be more useful from your own code.

Ok, so once we have a permission, we can use it to restrict access to particular actions:

code: null
class MyController extends JsecAuthBase { static accessControl = { permission(perm: new BasicPermission('myTarget', 'view' (+)), action: 'view')

permission(perm: new BasicPermission('myTarget', 'modify' (+)), only: 'edit', 'update' (+))

permission(perm: new BasicPermission('myTarget', 'create' (+)), only: 'create', 'save' (+)) }

… }

code: null
You can also use a permission to restrict access to particular domain objects managed by a controller:
code: null
class MyController extends JsecAuthBase { def view = { BasicPermission permission = new BasicPermission(params.name, "view") ThreadLocalSecurityContext securityContext = new ThreadLocalSecurityContext() if (!securityContext.implies(permission))) { redirect(controller:'auth', action:'unauthorized') return } } }
code: null
Note that if the user isn't logged in, this will simply redirect to the unauthorized page rather than prompting the user to log in. You may also want to restrict access to the controller or action with a role-based accessControl.

The realms

The above section showed how to restrict access to particular actions, but how are the role and permission requirements enforced? Well, {{JsecAuthBase}} provides a {{beforeInterceptor}} that delegates the role and permission checks to any realms that have been defined. The final step of the installation created a standard realm that uses domain classes to store the user, role, and permission information: {{grails-app/realms/DbRealm.groovy}}. This means that your web application is already secured. Unfortunately, without the user, role, and permission information in the database, the authority checks will always fail.

Currently, there are only two ways of getting that information into the database: on startup, or via your own user interface. The first option is the simplest:

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

class ApplicationBootStrap { def init = { servletContext -> def adminRole = JsecRole.findByName("Administrator") if(!adminRole){ adminRole = new JsecRole(name: 'Administrator') adminRole.save() }

def observerRole = JsecRole.findByName('Observer') if(!observerRole){ observerRole = new JsecRole(name: 'Observer') observerRole.save() }

// Create some users // Note that we store a hash of the user's password, // not the password itself. def admin = JsecUser.findByUsername('admin') if(!admin){ admin = new JsecUser(username: 'admin', passwordHash: DigestUtils.shaHex('changeit')) admin.save() new JsecUserRoleRel(user: admin, role: adminRole).save() new JsecUserRoleRel(user: admin, role: observerRole).save() }

def tarzan = JsecUser.findByUsername("tarzan") if(!tarzan){ tarzan = new JsecUser(username: 'tarzan', passwordHash: DigestUtils.shaHex('password')) tarzan.save() new JsecUserRoleRel(user: tarzan, role: observerRole).save() }

// Give the second user a direct permission. def p1 = new JsecPermission(type: 'BasicPermission', possibleActions: 'create,delete,modify,view') p1.save()

new JsecUserPermissionRel(user: tarzan, permission: p1, target: 'myTarget', actions: 'view').save()

… }

… }

The second option can readily be done by scaffolding all the Jsec* domain classes, although you have to remember to store the SHA hashed password in the database. Of course, a UI generated this way isn't great, but it will work.

Note that you can also assign permissions to roles via the JsecRolePermissionRel table. If a user is given a role that has permissions associated with it, then that user is automatically granted all those permissions.

The login screen

This release of the plugin comes with an {{AuthController}} and a login page. Unauthenticated users are redirected to this page when they attempt to access a secure page. The controller also comes with actions for logging out, {{signOut}}, and unauthorised access, {{unauthorised}}. You must currently provide your own links to the {{signOut}} action and a corresponding view.

You should edit {{signOut}} to redirect to the start page of your choice:

def signOut = {
   def threadContext = ThreadLocalSecurityContext.current()
   threadContext?.invalidate
   redirect(controller:"book", action:"index")
}