A comprehensive step by step Grails 4 tutorial on creating custom Spring Security custom user details
In this tutorial, we will show you how to implementing custom user details for Grails 4 and Spring Security web applications. As a default, the Grails 4 Spring Security generated user domain or entity has only username and role fields that can get or show in the SecurityTagLib. So, we will add additional fields to display user info or details in the SecurityTagLib.
The following tools, frameworks, and libraries are required for this tutorial:
Let’s get started with the main steps!
Before creating a new Grails 4 application, make sure that you have installed the latest Grails 4 version in your machine and can run the Grails 4 interactive console in the terminal or CMD. In the Mac terminal, we will use SDKman to install the latest Grails 4. To see the available Grails version in the SDKman, type this command.
sdk list grails
As you can see, there is some version of Grails 4 but we will install and use the stable version of Grails 4 by type this command.
sdk i grails 4.0.3
sdk u grails 4.0.3
Next, create a new Grails 4 application by type this command.
grails create-app securepage
Go to the newly created Grail 4 application. Then open the Grails project with your IDE or Text Editor.
cd securepage
code .
To working with Grails interactive console, type this command.
grails
If you see this error.
Error Error initializing classpath: Timeout of 120000 reached waiting for exclusive access to file: /Users/didin/.gradle/wrapper/dists/gradle-5.1.1-bin/90y9l8txxfw1s2o6ctiqeruwn/gradle-5.1.1-bin.zip (Use --stacktrace to see the full trace)
Just, remove .grails folder in the home directory then start again Grails interactive console.
rm -rf ~/.gradle
grails
For sanitation, start this Grails 4 application by type this command inside Grails interactive console.
run-app
Open your browser then go to “localhost:8080” and you should see this Grails page.
To stop or shutdown the running Grails server, type this command.
stop-app
To add the Grails Spring Security Plugin, open and edit “build.gradle” in the root of the project folder. Then add this line to the dependencies.
dependencies {
...
compile 'org.grails.plugins:spring-security-core:4.0.0'
...
}
Compile this project to download and install the Spring Security dependency.
compile
Still, on Grails interactive console, type this command to generate the User and Role domain class.
s2-quickstart com.djamware.securepage User Role
That command generates the User.groovy, Role.groovy, and UserRole.groovy domain class. Also, an additional configuration file “grails-app/conf/application.groovy”. The generated User.groovy look like this.
package com.djamware.securepage
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import grails.compiler.GrailsCompileStatic
@GrailsCompileStatic
@EqualsAndHashCode(includes='username')
@ToString(includes='username', includeNames=true, includePackage=false)
class User implements Serializable {
private static final long serialVersionUID = 1
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Set<Role> getAuthorities() {
(UserRole.findAllByUser(this) as List<UserRole>)*.role as Set<Role>
}
static constraints = {
password nullable: false, blank: false, password: true
username nullable: false, blank: false, unique: true
}
static mapping = {
password column: '`password`'
}
}
The generated Role.groovy looks like this.
package com.djamware.securepage
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import grails.compiler.GrailsCompileStatic
@GrailsCompileStatic
@EqualsAndHashCode(includes='authority')
@ToString(includes='authority', includeNames=true, includePackage=false)
class Role implements Serializable {
private static final long serialVersionUID = 1
String authority
static constraints = {
authority nullable: false, blank: false, unique: true
}
static mapping = {
cache true
}
}
The generated UserRole.groovy looks like this.
package com.djamware.securepage
import grails.gorm.DetachedCriteria
import groovy.transform.ToString
import org.codehaus.groovy.util.HashCodeHelper
import grails.compiler.GrailsCompileStatic
@GrailsCompileStatic
@ToString(cache=true, includeNames=true, includePackage=false)
class UserRole implements Serializable {
private static final long serialVersionUID = 1
User user
Role role
@Override
boolean equals(other) {
if (other instanceof UserRole) {
other.userId == user?.id && other.roleId == role?.id
}
}
@Override
int hashCode() {
int hashCode = HashCodeHelper.initHash()
if (user) {
hashCode = HashCodeHelper.updateHash(hashCode, user.id)
}
if (role) {
hashCode = HashCodeHelper.updateHash(hashCode, role.id)
}
hashCode
}
static UserRole get(long userId, long roleId) {
criteriaFor(userId, roleId).get()
}
static boolean exists(long userId, long roleId) {
criteriaFor(userId, roleId).count()
}
private static DetachedCriteria criteriaFor(long userId, long roleId) {
UserRole.where {
user == User.load(userId) &&
role == Role.load(roleId)
}
}
static UserRole create(User user, Role role, boolean flush = false) {
def instance = new UserRole(user: user, role: role)
instance.save(flush: flush)
instance
}
static boolean remove(User u, Role r) {
if (u != null && r != null) {
UserRole.where { user == u && role == r }.deleteAll()
}
}
static int removeAll(User u) {
u == null ? 0 : UserRole.where { user == u }.deleteAll() as int
}
static int removeAll(Role r) {
r == null ? 0 : UserRole.where { role == r }.deleteAll() as int
}
static constraints = {
user nullable: false
role nullable: false, validator: { Role r, UserRole ur ->
if (ur.user?.id) {
if (UserRole.exists(ur.user.id, r.id)) {
return ['userRole.exists']
}
}
}
}
static mapping = {
id composite: ['user', 'role']
version false
}
}
You don’t have to worry about login page view, it automatically handles by the Spring Security.
#grails #spring #security #web-development #developer