httpSession in Grails - grails

I need to access the domain class User of the current session. The following code works:
class RatingController {
def rate = {
def rating = params.rating
def artist = Artist.get( params.id )
def user = User.get(1)
user.addToRatings(new Rating(artist:artist, rating:rating))
user.save()
render(template: "/artist/rate", model: [artist: artist, rating: rating])
}
}
But instead of explicitly get the user with ID equal 1 (User.get(1)) I need to access the user of the current session. I tried the following code, but it doesn't work:
class RatingController {
def rate = {
def rating = params.rating
def artist = Artist.get( params.id )
def user = user.session
user.addToRatings(new Rating(artist:artist, rating:rating))
user.save()
render(template: "/artist/rate", model: [artist: artist, rating: rating])
}
}
I'm still struggling to fully understand the httpSession concept, so a little help would be great.
Thank in advance.
UPDATE
In my UserController, my authentication looks like this:
def authenticate = {
def user = User.findByLoginAndPassword(params.login, params.password)
if(user){
session.user = user
flash.message = "Hello ${user.name}!"
redirect(controller:"event", action:"list")
}else{
flash.message = "Sorry, ${params.login}. Please try again."
redirect(action:"create")
}
}

the http session is nothing more than data that is maintained among a sequence of requests from a single source, like a browser.
To put something on the session, just do
session.setAttribute("key", value)
and to get data off the session just do
session.getAttribute("key")
Grails also adds some fanciness to session access as outlined here. Their example shows
def user = session["user"]
session["user"] = "John"
asset "John" == session.user
Note that if you are using a grails plugin for authentication and authorization, it will probably provide a way to get the user. For example Spring Security gives you the following
springSecurityService.getCurrentUser()
depending on the details of your plugin, that user might or might not be on the session.

In your code I noticed you wrote
def user = user.session
When I think you mean
def user = session.user
The other thing I do is make it session.userId ie session.userId = user.id and then
def user = User.get(session.userId)
Not sure if that's necessary.

You'll need to use .merge():
user.merge(flush: true)
This is because the instance is detached from the persistence context when you save it to HttpSession. Here is the doc from grails:
http://grails.org/doc/2.3.1/ref/Domain%20Classes/merge.html

Related

Grails/Groovy: Cannot cast object to java.util.Set (twitter clone project)

I am trying to make a follow user like in twitter. I'm getting an exception when I try to save the user of the currently logged in session user.
Error 500: Internal Server Error
URI - /blog-dwit/user/follow/3
Class - org.codehaus.groovy.runtime.typehandling.GroovyCastException
Message - Cannot cast object 'blog.dwit.User : 3' with class 'blog.dwit.User' to class 'java.util.Set'
User domain:
class User {
String email_id;
String password;
Profile profile
static hasMany = [ posts:Post, following: User ]
}
Controller action
def follow(){
def followUser = User.get(params.id)
def user = User.get(session.user)
user.following = followUser
user.save()
}
When adding instances to collections you have to use the addTo* method for the corresponding collection. The documentation explains this in further detail.
Your action should look like this:
def follow(){
def followUser = User.get(params.id)
def user = User.get(session.user)
user.addToFollowing(followUser)
user.save()
}

Grails find in relationship

I'm breaking my head into wall about this logic, I have 2 domains, User and RSS. When the user add a RSS, I have to compare if it's not duplicated URL in my db by given another URL in the same user.
class RSS {
Long id
String link
static belongsTo = [user:User]
}
class User {
Long id
Long uid //facebook
String name
static hasMany = [rss:RSS]
}
def addRSS(){
//logic url is valid or not
...
def user = User.findByUid(data.id) //get User uid and then by this uid, i can get the all RSS url
//and compare like if(db_url == given_url) ...
}
I tried many ways and I had no success.
You could also use one of the findOrSaveWhere or findOrCreateWhere methods
def url = 'some url from user' //data.url I would assume
def user = User.findByUid(data.id)
RSS.findOrSaveWhere(url: url, user: user)
If it's in the db it will fetch it for you if not it will create it for you. The documentation explains the difference between the *Save* and *Create*
Simple join would do I think:
def existing = RSS.withCriteria{
eq 'link', url
eq 'user.id', userId
}
or
def existing = RSS.withCriteria{
eq 'link', url
user{ eq 'uid', uidd }
}
if( existing ) return
else doSave()

springSecurityService.principal.id giving firstname instead of userid

I am using springSecurityCore plugin in my application and after user login in the appStartupController, I do like
def index = {
if (springSecurityService.isLoggedIn()) {
session.loginId=springSecurityService.principal.id
def userRole=UserRole.findAllByUserAndRole(User.get(session.loginId), Role.findByAuthority('ROLE_USERSDASH'))
if(userRole){
redirect(controller:'dashboard',action:'getRiskUserDashboard')
}
}
}
when I read session.loginId in the header.gsp I see the firstname from the User table is printed.
I need to have the userId field in the User table mapped to the session.loginId.
How to do that?
You can get the current User by calling the following:
def user = springSecurityService.getCurrentUser()
And then just pass that user into the UserRole find method.

Why won't #Secured annotations work after a grails spring-security manual login?

I've been attempting to log in a user automatically after a successful signup using grails with the spring-security-core plugin. While the forced login works, and all the authorities etc. are loaded, the #Secured annotations in other controllers won't recognise the granted authorities and consequently the browser gets stuck in a redirect loop between the secured and login pages.
My login action:
def forceLogin = {
PSysuser sysuser = flash.sysuser;
String username = flash.username ?: params.username;
String password = flash.password ?: params.password;
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
sysuser?.username ?: username,
sysuser?.password ?: password
);
request.session;
token.details = new WebAuthenticationDetails(request);
Authentication authenticatedUser = authenticationManager.authenticate(token);
SecurityContextHolder.context.authentication = authenticatedUser;
springSecurityService.reauthenticate(username, password); //doesn't appear to work, but doesn't hurt either.
redirect action:auth;
}
Does anyone know how I can get the annotations to work properly?
If you are using the spring-security-plugin, take a look at some of the helper classes. More specifically, check out the reauthenticate method of the SpringSecurityService. Here is an example from Burt's amazing documentation:
class UserController {
def springSecurityService
def update = {
def userInstance = User.get(params.id)
params.salt = person.salt
if (userInstance.password != params.password) {
params.password = springSecurityService.encodePassword(params.password, salt)
def salt = … // e.g. randomly generated using some utility method
params.salt = salt
}
userInstance.properties = params
if (!userInstance.save(flush: true)) {
render view: 'edit', model: [userInstance: userInstance]
return
}
if (springSecurityService.loggedIn &&
springSecurityService.principal.username == userInstance.username) {
springSecurityService.reauthenticate userInstance.username
}
flash.message = "The user was updated"
redirect action: show, id: userInstance.id
}
}
So, turns out that it wasn't the #Secured annotations at all, but the session-based authentication code left over from before spring-security was implemented.
After adding the correct object to the session scope, the problem went away.
ARGH!

Grails and Spring Security: How do I get the authenticated user from within a controller?

I recently moved from the JSecurity plugin to Spring Security. How do I get the authenticated user from within my controllers?
It's not currently documented, but in the plugin installation file, there are 3 methods that it adds to every controller so that you don't actually have to inject the authenticationService:
private void addControllerMethods(MetaClass mc) {
mc.getAuthUserDomain = {
def principal = SCH.context?.authentication?.principal
if (principal != null && principal != 'anonymousUser') {
return principal?.domainClass
}
return null
}
mc.getPrincipalInfo = {
return SCH.context?.authentication?.principal
}
mc.isUserLogon = {
def principal = SCH.context?.authentication?.principal
return principal != null && principal != 'anonymousUser'
}
}
This means that you can just call
principalInfo
To get the principal object. It also has "isUserLogin" to see if the user is logged and "authUserDomain" to get the actual domain class instance (the Person/User) associated with the principal of the logged in user.
The following code is from the Spring Security Core Plugin (Version: 1.1.2) - Reference Documentation - Section 6.2
grails.plugins.springsecurity.SpringSecurityService provides security utility functions. It is a regular Grails service, so you use dependency injection to inject it into a controller, service, taglib, and so on:
class SomeController {
def springSecurityService
def someAction = {
def user = springSecurityService.currentUser
…
}
}
I'm using 0.5.1 and the following works for me:
class EventController {
def authenticateService
def list = {
def user = authenticateService.principal()
def username = user?.getUsername()
.....
.....
}
}
Nowadays, I think the way to do it is:
def user = getAuthenticatedUser()
You can get current User by this way also
class AnyController {
def springSecurityService
def someAction = {
def user = User.get(springSecurityService.principal.id)
}
}
Use this code:
if (springSecurityService.isLoggedIn()){
println "Logged In"
}

Resources