sullivan
sullivan

Reputation: 360

Grails: Redirect from called method

Good morning Community.

I use Grails for a backend app and therefore want to check if users are allowed to do the requested action.

So I call checkPermission() at the begin and redirect to the index page if user is not allowed. But I'm occuring this error:

Cannot issue a redirect(..) here. A previous call to redirect(..) has already redirected the response.

Extract from my source:

def test() {
  println("test()")
  checkPermission([TaskXYZ])
  println("AfterCheck")
  redirect(action: "profile", params: [lang: params.lang])
}    

private checkPermission(def tasks) {
  println("checkPermission()")
  if ( ! userService.isAllowed(tasks)) {
    println("NotAllowed")
    flash.error = message(code: "msg.actionIsNotAllowed")
    redirect(action: "index", params: [lang: params.lang])
    return false
  }
}

Output:

test()
checkPermission()
NotAllowed
AfterCheck

So the redirect doesn't work from the private method and return false causes the return to the called method.

What can I do alternatively? I considered beforeInterceptor, but I need to pass custom parameters for every method.

Thanks, Rob.

Upvotes: 0

Views: 986

Answers (2)

Joshua Moore
Joshua Moore

Reputation: 24776

The problem you are encountering is that issuing a redirect doesn't stop the execution of the controller method/action. After your redirect within checkPermission your controller code continues to execute after checkPermission and is encountering the next redirect. You need to return from your controller if your checkPermission is to terminate the execution of the controller method/action.

For example:

...
private boolean checkPermission(def tasks) { ... }
...
if (!checkPermission([TaskXYZ])) return
...

Upvotes: 2

Kamil Mikolajczyk
Kamil Mikolajczyk

Reputation: 911

you can't call redirect() method twice during one request, though that's what your code is doing, but you can simply change it in numerous ways, i.e.

def test() {
  boolean hasPermission = checkPermission([TaskXYZ])
  if (!hasPermission) {
      return ; // you have to finish the action, because you already called redirect inside checkPermission() method
  }
  // do further actions when permission granted
  redirect(action: "profile", params: [lang: params.lang])
}    

private checkPermission(def tasks) {
  if ( ! userService.isAllowed(tasks)) {
    return false
  }
  return true
}

you could also improve it so that you can make different redirects:

def test() {
  boolean checkPermissionResult = checkPermission([TaskXYZ])
  if (checkPermissionResult != null) {
      return redirect(checkPermissionResult)
  }
  // do further actions when permission granted
  redirect(action: "profile", params: [lang: params.lang])
}    

private checkPermission(def tasks) {
  if ( ! userService.isAllowed(tasks)) {
    return [action: "index", params: [lang: params.lang]]
  } else if (userService.userNotExists()) { // or any different situatoin
    return [action: "register", params: [lang: params.lang]]
  }
  return null
}

Upvotes: 2

Related Questions