4

我正在 Grails 中编写一个小型 Web 应用程序,为了确保所有用户都经过身份验证,我使用了以下过滤器:

class LoginFilters {
  static filters = {
    loginCheck(controller:'*', action:'*') {
      before = {
        if (session.user_id) {
          request.user = User.get(session.user_id)
        } else if (!actionName.equals("login")) {
          redirect(controller: "login", action: "login")
          return false
        }
      }
    }
  }
}

所有控制器方法都从读取请求对象的用户属性开始:

def actionName = {
   def user = request.user
   ...
}

上面的代码有效,但我宁愿避免所有控制器方法中的重复代码。过滤器是否可以将用户对象绑定到一个名为“user”而不是“request.user”的变量,所有控制器都可以访问该变量?

我知道可能存在范围界定问题使这成为不可能,但 Grails 框架似乎能够在幕后创造相当多的魔力,所以我认为这可能值得一问。

4

3 回答 3

1

在控制器中使用 beforeInterceptor 可能会有所帮助:

class LoginController {

    def user

    def beforeInterceptor = {
        user = request.user
    }

    def index = { 
        render text:"index: ${user}"        
    }

    def test = {
        render text:"test: ${user}"         
    }
}
于 2009-01-31T03:34:37.527 回答
1

I think it generally not a good idea insert the user object into the request object every time:

The request lifetime is very short, so you might end up making round trips to caches or even worse to the database on each http-request to retrieve an object, that you might not even need and that get's deleted immideately afterwards. So if you must, better store the whole object in the session instead of just the id.

Generally, I'd suggest you write a AuthenticationService with a method isLoggedIn() that returns true when the user is authenticated and a method getLoggedInUser() that returns this object.

class AuthenticationService {
    def transactional = false
    boolean isLoggedIn() { return session.user_id }
    def getLoggedInUser() { return User.get(session.user_id) }
}

Then you use the Filter for redirection if not authenticated, and maybe the Interceptor for storing the local reference user = authenticationService.loggedInUser. But also I don't think this the best way to go. I suggest you'd create an abstract AuthenticationAwareController as base class for all your controllers in src/groovy and there have the convenience method like user

class AuthenticationAwareController {
    def authenticationService
    def getUser() { return authenticationService.loggedInUser() }
}

This way, you can later change you mind about storing the user however you like and don't have to change your code. Also you benefit from Caches in Hibernate, that share already retrieved user object instances between different sessions, so db roundtrips are avoided.

You still should check the retrieved user object for validity or throw an AuthenticationException in case the retrieval does not succeed. (Maybe something like AuthenticationService.getLoggedInUser(failOnError = false).)

You can even make this Service/ControllerBase a small plugin an reuse that on every application or go directly with the spring security plugin... ;-)

于 2010-12-08T17:52:52.203 回答
0

I think you can do this but is it really worth the trouble? It seems to me your only advantage is typing "user" instead of "request.user". Not a big gain. Anyway, I think you could follow the instructions in "12.7 Adding Dynamic Methods at Runtime" of the User Guide. I think that if you created a dynamic method "getUser() {return request.user}" that the Groovy JavaBeans getter/setter access would allow you to simply reference "user" the way you want.

If you do add a dynamic method you might want to skip the filter and do it all in the dynamic method.

于 2009-02-01T07:01:24.457 回答