views:

240

answers:

1

I have secured my Grails app using the ACEGI plugin and am using annotations on my controller methods to prompt the user to login.

My app has a static HTML front page with a login link on it which redirects to the login/auth page. On a successful login I want to load my own custom page for the authenticated user, called person/mainpage.

In my LoginController there is the following code...

def index = {
    if (isLoggedIn()) {
        redirect uri: '/'
    }
    else {
        redirect action: auth, params: params
    }
}

/**
 * Show the login page.
 */
def auth = {

    nocache response

    if (isLoggedIn()) {
        redirect uri: '/'
        return
    }

    String view
    String postUrl
    def config = authenticateService.securityConfig.security
    if (config.useOpenId) {
        view = 'openIdAuth'
        postUrl = "${request.contextPath}/login/openIdAuthenticate"
    }
    else if (config.useFacebook) {
        view = 'facebookAuth'
        postUrl = "${request.contextPath}${config.facebook.filterProcessesUrl}"
    }
    else {
        view = 'auth'
        postUrl = "${request.contextPath}${config.filterProcessesUrl}"
    }

    render view: view, model: [postUrl: postUrl]
}

This redirects the successful login back to the main page of the application (/), which is not what I want. Googling for a little while I found that I could define a default target for my authentication in securityconfig.groovy like this..

defaultTargetUrl = "/person/mainpage"

My question is how to identify which user logged in when I land on my mainpage action in my PersonController?

At first I changed my index action in LoginController to redirect to my page like this...

def index = {
    if (isLoggedIn()) {
        redirect controller: person, action: mainpage, params: params 
    }
    else {
        redirect action: auth, params: params
    }
}

but the id of the logged in person does not appear in the params (which I think I am happy about because it seems crazy to be able to pull up pages just by defining a user row ID as a url parameter).

So what's the right way to do this? Basically I want my person/mainpage action to be able to resolve the currently logged in user.

+2  A: 

You can access the logged in user using authenticateService. To get the user/person domain instance call authenticateService.userDomain() and to just get the Authentication (which has a getUsername() method that might be sufficient) call authenticateService.principal(). If your defaultTargetUrl is "/person/mainpage" then your PersonController's 'mainpage' action would look something like this:

class PersonController {

   def authenticateService

   def mainpage = {
      def user = authenticateService.userDomain()
      if (user) {
         log.info "you're logged in as $user.username"
      }
      else {
         log.info "you're not logged in"
      }
      [user: user]
   }
}

and then you'd have the 'user' available in mainpage.gsp to render data from.

Burt Beckwith
I had almost got there. I was using authenticateService.principal() which appears to be a different class. I have been looking for documentation for the authenticateService interface, can you point me towards it?
Simon
As a matter of interest, is this the accepted approach for this sort of issue. It feels like a bit of a hack and the context of the user ought to be available without having to go back to the authentication service manually.
Simon
The Principal is available from the SecurityContext and the user domain instance is attached to that. You can go directly to that but AuthenticateService hides the implementation details for you.The plugin also injects a 'getAuthUserDomain()' method into controllers that does the same thing.
Burt Beckwith
should I expect the personInstance that I retrieve from userDomain to be fully populated, i.e. with data held in collections via one-to-many relationships? I am getting a lazy loading error on a collection property of my Person class.
Simon
No, it's a disconnected instance. Either call user.merge() or reload it via "user = User.get(user.id)"
Burt Beckwith