I'm a new developer for groovy grails and I have a table named user under the database test.
I succeed to login to that database by using grails but I couldn't succeed to register the new user.
Here is my register.gsp
<g:form controller="user" action="registration">
<fieldset class="form">
<div class="fieldcontation ${hasErrors(bean: userInstance, field: 'fullName', 'error')}">
<label for="fullName">
<g:message code="endUser.fullName.label" default="Full Name" />
</label>
<g:textField name="fullName" value="${userInstance?.fullName}"/>
</div>
<div class="fieldcontation ${hasErrors(bean: userInstance, field: 'userName', 'error')}">
<label for="userName">
<g:message code="endUser.userName.label" default="User Name" />
</label>
<g:textField name="userName" value="${userInstance?.userName}"/>
</div>
<div class="fieldcontain ${hasErrors(bean: userInstance, field: 'password', 'error')} ">
<label for="password">
<g:message code="endUser.password.label" default="Password"/>
</label>
<g:field type="password" name="password" value="${userInstance?.password}"/>
</div>
</fieldset>
<fieldset class="buttons">
<g:submitButton name="register" class="save" value="Register" />
</fieldset>
</g:form>
here is my UserController.groovy
package test
import java.sql.SQLClientInfoException;
import javax.activation.DataSource;
import grails.converters.JSON
class UserController {
def index() {
redirect(action:"login")
}
def register = {}
def login = {}
def registration = {
def b = new User(fullName:params.fullName, userName:params.userName, password:params.password)
b.save()
render (b as JSON)
}
def authenticate = {
def user = User.findByUserNameAndPassword(params.userName, params.password)
if (user){
def userMap = [:]
userMap.put("login", "true")
userMap.put("name", user.fullName)
userMap.put("password", user.password)
render (userMap as JSON)
}else{
flash.message = "Sorry, ${params.userName}, Please try again."
redirect(action:"login")
}
}
def logout = {
flash.message = "Goodbye ${session.user.fullName}"
session.user = null
redirect(action:"login")
}
}
After this method , I had this error
http://postimg.org/image/gbitzsokp/
But I couldn't understand what it tried to say
here is my DataSource.groovy
dataSource {
pooled = true
jmxExport = true
driverClassName = "com.mysql.jdbc.Driver"
username = "admin"
password = "admin"
}
hibernate {
cache.use_second_level_cache = true
cache.use_query_cache = false
cache.provider_class='net.sf.ehcache.hibernate.EhCacheProvider'
}
// environment specific settings
environments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
url = "jdbc:mysql://localhost:3306/test"
}
}
test {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://localhost:3306/test"
}
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://localhost:3306/test"
}
}
}
My domain class User.groovy
package test
class User {
String userName
String password
String fullName
String toString(){
"${fullName}"
}
static constraints = {
fullName()
userName(unique: true)
//password(password=true)
}
}
Plug-in's
plugins {
build ":tomcat:7.0.55"
compile ":scaffolding:2.1.2"
compile ':cache:1.1.8'
compile ":asset-pipeline:1.9.9"
compile ":simpledb:0.5"
runtime ":hibernate4:4.3.6.1" // or ":hibernate:3.6.10.18"
runtime ":database-migration:1.4.0"
runtime ":jquery:1.11.1"
}
I can immediately assure every information you need
Thank you
My Grails version is 2.4.4
As #saw303 mentioned, GORM provides what you're looking for. So there's no need to write SQL statements.
Workflow
I'm assuming the workflow you need is something like this:
The register action renders register.gsp, the registration form.
When the registration form is submitted the registration action handles the request. If all goes well, the user is set in the session scope and the browser is redirected somewhere, such as the home page. Otherwise, the browser is redirected to the register action and the validation errors are displayed in the registration form.
Here's how to create such a workflow.
Registration action
Begin by making a number of changes to the registration action.
import grails.transaction.Transactional
class UserController {
// NOTE: Making the method Transactional avoids having to flush saves.
#Transactional
def registration() {
def user = new User(params).save()
if(user.hasErrors()) {
/*
* On failure, redirect back to registration form,
* and pass the User instance to the GSP page in the
* flash scope so that validation errors can be rendered.
*/
flash.userInstance = user
redirect action: 'register'
} else {
/* On success, place User instance in session scope,
* and redirect to home page.
*/
session.user = user
redirect uri: '/'
}
}
}
I added the Transactional annotation so the flushing of GORM saves are handled automatically.
registration is now a method instead of a Closure. It's the new way.
register.gsp
To render the validation errors in the registration form, change the hasErrors() calls from bean: userInstance to model: flash?.userInstance For example, for the fullName property, do ${hasErrors(model: flash?.userInstance, field: 'fullName', 'error')}
Related
I've created a form that a user updates to update his profile. When I update the details of the user, and I log out and log in again, I get access denied. I found out that the reason for this was with the authority, every time I updated the table, other details were saved, but the authority is lost and as a result, access is denied.
So I would like to assign the role again within the form but without the user having any input. Any advise on how to implement that is appreciated.
below is my gsp;
<div class="form-group">
<label class="col-sm-5 control-label">
Roles
</label>
<div class="col-sm-5 ">
<g:each in="${roles}" var="role" status="i">
<div class="checkbox-inline">
<g:checkBox name="roles" value="${role.id}"
checked="${role.authority == "ROLE_MEMBER" ? 'true': user.hasRole(role)}"/>
<label for="roles[${i}]">${role.authority}</label>
</div>
</g:each>
</div>
</div>
<div class="form-group">
<div class="${hasErrors(bean: user, field: 'natureOfIndividual', 'error')} required">
<label for="natureOfIndividual" class="col-sm-5 control-label">
<g:message code="user.natureOfIndividual.label" default="Nature of Individual"/>
</label>
<div class="col-sm-5">
<g:select name="natureOfIndividual"
from="${['Local', 'Foreign']}"
class="form-control" noSelection="['': '-----Select-----']"
value="${user?.natureOfIndividual}"/>
</div>
</div>
</div>
With this code am not able to see the checkboxes. Still finding out why. But ultimately, I don't want the user to see any checkboxes, I want to assign the authority without his/her input.
I got a solution. In my UserController.groovy, there was updateRoles method that was called in update method. I commented out the method call. And now the roles are not affected after an update. Below is the code;
#Transactional
def update(User user) {
if (user == null) {
transactionStatus.setRollbackOnly()
notFound()
return
}
if (user.hasErrors()) {
transactionStatus.setRollbackOnly()
respond user.errors, view: 'edit'
return
}
boolean passChange = false
if (user.isDirty('password')) {
passChange = true
}
user.save flush: true
//updateRoles(user)
request.withFormat {
form multipartForm {
if (passChange) {
flash.message = "A user with username '${params.username}' and password '${params.password}' has been Updated"
} else {
flash.message = "Your profile has been updated"
}
redirect user
}
'*' { respond user, [status: OK] }
}
}
private updateRoles(User user) {
UserRole.removeAll(user)
List roleIds = params.roles instanceof String ? [params.roles] : params.roles
roleIds?.each { roleId ->
def role = Role.get(roleId)
UserRole.create(user, role, true)
}
}
As you've seen, I have commented out the method call in the update method. So when users update their details, their authorization is still preserved.
I have gsp with two textfield for firstname-lastname and reCaptcha. What I want is for every wrong captcha code the user's input for firstname and last name won't be erased.
snippet for controller:
***captcha_code****
if (result) {
def person = new Person(params)
person.save()
render "Success!"
} else {
flash.message = message(code: 'forgotPassword.captcha.wrong')
redirect(controller:'person', action:'form')
}
snipper for form.gsp
***captcha_code_here***
<g:form controller="person" action="save">
<label>First Name: </label>
<g:textField name="firstName"/><br/>
<label>Last Name: </label>
<g:textField name="lastName"/><br/>
<g:if test="${flash.message}">
<div class="message" role="status" style="font-size: medium;color: green;">${flash.message}</div>
</g:if>
***captcha_code_here***
<g:actionSubmit value="Save"/>
To repopulate the fields you can use the same flash scope you're using for the message. On error, add the first and last name to the flash scope, and then in your GSP use those values when they are available:
PersonController
class PersonController {
def save() {
...
if(/* recaptcha failed */) {
flash.firstName = params.firstName
flash.lastName = params.lastName
}
...
}
}
GSP
<label>First Name: </label>
<g:textField name="firstName" value="${flash.firstName ?: ''}"/><br/>
<label>Last Name: </label>
<g:textField name="lastName" value="${flash.lastName ?: ''}"/><br/>
In Controller Action, send back fields that you want to be repopulated.
I have a User domain with a flag for security officer and a Location domain to hold all locations in my web app. I want to allow an administrator to assign a primary and secondary security officer to any location from a pick list of all users with the security officer flag checked. I have this working in a hand-made MVC structure, but I'm currently playing with scaffolding and have run into a strange error I can't figure out. My Location domain is coded as
class Location {
static hasMany = [users:User]
Integer id
...
String address
String city
State state
String zip
...
User primarySecurityOfficer
User secondarySecurityOfficer
static mapping = {
table 'location'
id generator: 'identity'
sort "state"
version false
}
static constraints = {
...
address(blank: false, nullable: false)
city(blank: false, nullable: false)
state(blank: false, nullable: false)
zip(blank: false, nullable: false, size: 5..5)
...
primarySecurityOfficer(blank: true, nullable: true)
secondarySecurityOfficer(blank: true, nullable: true)
}
}
and I generated the views with grails generate-all Location. I modified the security officer selection in the generated _form.gsp to
<div class="fieldcontain ${hasErrors(bean: locationInstance, field: 'primarySecurityOfficer', 'error')}">
<label for="primarySecurityOfficer">
<g:message code="location.primarySecurityOfficer.label" default="Primary Security Officer" />
</label>
<g:select id="primarySecurityOfficer" name="primarySecurityOfficer" value="${locationInstance?.primarySecurityOfficer?.employeeNumber}" from="${securityOfficers}" optionKey="employeeNumber" optionValue="${{it.firstName + ' ' + it.lastName}}" noSelection="${['null':' ']}" disabled="${disabled}"/>
</div>
<div class="fieldcontain ${hasErrors(bean: locationInstance, field: 'secondarySecurityOfficer', 'error')}">
<label for="secondarySecurityOfficer">
<g:message code="location.secondarySecurityOfficer.label" default="Secondary Security Officer" />
</label>
<g:select id="secondarySecurityOfficer" name="secondarySecurityOfficer" value="${locationInstance?.secondarySecurityOfficer?.employeeNumber}" from="${securityOfficers}" optionKey="employeeNumber" optionValue="${{it.firstName + ' ' + it.lastName}}" noSelection="${['null':' ']}" disabled="${disabled}"/>
</div>
and the controller's create and save auto-generated actions (modified to send the view the security officer list) are
def create() {
def securityOfficers = User.findAll("from User as u where u.securityOfficer='1'")
println params
respond new Location(params), model: [ securityOfficers:securityOfficers ]
}
#Transactional
def save(Location locationInstance) {
def securityOfficers = User.findAll("from User as u where u.securityOfficer='1'")
if (locationInstance == null) {
notFound()
return
}
if (locationInstance.hasErrors()) {
respond locationInstance.errors, view:'create', model: [ securityOfficers: securityOfficers ]
return
}
locationInstance.save flush:true
request.withFormat {
form {
flash.message = message(code: 'default.created.message', args: [message(code: 'locationInstance.label', default: 'Location'), locationInstance.id])
redirect locationInstance
}
'*' { respond locationInstance, [status: CREATED], model: [ securityOfficers:securityOfficers ] }
}
}
The error I'm getting is that if I select any security officers and try to save a new location, I get the error Could not find matching constructor for: User(java.lang.String). If I leave the selector blank, the location will save successfully. Any ideas why?
Edit 1: Interesting find from tinkering around. I can successfully save security officers to locations if I change the view code to
<div class="fieldcontain ${hasErrors(bean: locationInstance, field: 'primarySecurityOfficer', 'error')}">
<label for="primarySecurityOfficer">
<g:message code="location.primarySecurityOfficer.label" default="Primary Security Officer" />
</label>
<g:select id="primarySecurityOfficer.employeeNumber" name="primarySecurityOfficer.employeeNumber" value="${locationInstance?.primarySecurityOfficer?.employeeNumber}" from="${securityOfficers}" optionKey="employeeNumber" optionValue="${{it.firstName + ' ' + it.lastName}}" noSelection="${['null':' ']}" disabled="${disabled}"/>
</div>
<div class="fieldcontain ${hasErrors(bean: locationInstance, field: 'secondarySecurityOfficer', 'error')}">
<label for="secondarySecurityOfficer">
<g:message code="location.secondarySecurityOfficer.label" default="Secondary Security Officer" />
</label>
<g:select id="secondarySecurityOfficer.employeeNumber" name="secondarySecurityOfficer.employeeNumber" value="${locationInstance?.secondarySecurityOfficer?.employeeNumber}" from="${securityOfficers}" optionKey="employeeNumber" optionValue="${{it.firstName + ' ' + it.lastName}}" noSelection="${['null':' ']}" disabled="${disabled}"/>
</div>
But now I cannot save WITHOUT a security officer. The error I get if I attempt to is Unparseable number: "null".
I am trying to configure the spring-security 2.0-RC2 plugin to work with my Grails application. I am able to get it to insert my default admin user with a hashed password into mongodb. I have also configured spring security to use emailAddress instead of username as the username field for authentication.
When I attempt to login (with the correct credentials) I am getting an authentication failed error. I'm a bit stumped as to what I am doing wrong. I probably am missing something small that causes this not to work. My configuration is included below.
In Config.groovy I have the standard configuration and specify usernamePropertyName to point to the email address field instead of username.
grails.plugin.springsecurity.userLookup.userDomainClassName = 'model.Person'
grails.plugin.springsecurity.userLookup.usernamePropertyName='email'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'model.PersonRole'
grails.plugin.springsecurity.authority.className = 'model.Role'
grails.plugin.springsecurity.securityConfigType = SecurityConfigType.InterceptUrlMap
//Configure URL Restrictions
grails.plugin.springsecurity.interceptUrlMap = [
'/login/**': [
'IS_AUTHENTICATED_ANONYMOUSLY'
],
'/static/**': [
'IS_AUTHENTICATED_ANONYMOUSLY'
],
'/**': [
'IS_AUTHENTICATED_REMEMBERED']
]
grails.plugin.springsecurity.password.algorithm = 'SHA-256'
I then have a Person.groovy file that was generated by spring security then modified to change username to email address. The generated PersonRole.groovy and Role.groovy haven't been modified.
package model
class Person {
transient springSecurityService
String id
String firstName
String lastName
String emailAddress
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static transients = ['springSecurityService']
static constraints = {
emailAddress blank: false, unique: true
password blank: false
}
static mapping = { password column: '`password`' }
Set<Role> getAuthorities() {
PersonRole.findAllByPerson(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
In my BootStrap.groovy I create a default admin user unless one already exists:
def adminUser = Person.findByEmailAddress('admin#test.com') ?: new Person(
firstName: 'Admin',
lastName: 'User',
emailAddress: 'admin#test.com',
password: springSecurityService.encodePassword('admin'),
enabled: true).save(failOnError: true)
I also created a custom auth.gsp file as follows, but I have also tried using the default one with the same result.
<form action="${postUrl}" method="POST" autocomplete="off">
<h4>Sign in</h4>
<g:if test="${flash.message}">
<div class="alert alert-danger" style="padding: 10px">${flash.message}</div>
</g:if>
<p>
<input type="email" class="form-control" placeholder="Email address" name="j_username" autofocus />
</p>
<p>
<input type="password" class="form-control" placeholder="Password" name="j_password" />
</p>
<input type="submit" class="btn btn-lg btn-primary btn-block" value="${message(code: 'springSecurity.login.button')}" />
</form>
So, does anyone see anything I am missing that would stop authentication from working?
You're double-encoding the password. It's done in the Person class in beforeInsert, and you do it again in the BootStrap code. Change
password: springSecurityService.encodePassword('admin'),
to
password: 'admin',
How can I access the current logged in user username with springSecurity in the gsp view, or more specifically, use this value in a textfield?
This solution below doesn't work:
value="${sec.loggedInUserInfo(field:'username')}"
The following lines both work correctly in my test.
<input name="username" type="text" value="${sec.username()}" />
<input name="username" type="text" value="${sec.loggedInUserInfo(field: 'username')}" />
Error you've got might be from other place. Could you test by only use that input tag in GSP?
Custom Taglib Option to get various information about the logged in the user into the view.
ExamplNameTagLib.groovy
class ExamplNameTagLib {
static namespace = 'foo'
def springSecurityService
def currentUserProps = { attrs ->
def user = springSecurityService.getCurrentUser()
if (user) {
if (attrs.username) {
out << user.username
} else if (attrs.firstName) {
out << user.firstName
} else if (attrs.lastName) {
out << user.lastName
} else if (attrs.email) {
out << user.email
}
}
}
}
exampleViewPage.gsp
//Return username from taglib of the logged in user
<g:field type="text"
name="username"
value="${foo.currentUserProps(username: true)}" />
//Return email from taglib of the logged in user
<g:field type="email"
name="email"
value="${foo.currentUserProps(email: true)}"/>