【问题标题】:Defining controller accessible variables from filters in Grails从 Grails 中的过滤器定义控制器可访问变量
【发布时间】:2010-10-04 09:10:30
【问题描述】:

我正在 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 框架似乎能够在幕后创造相当多的魔力,所以我认为这可能值得一问。

【问题讨论】:

    标签: authentication grails controller


    【解决方案1】:

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

    class LoginController {
    
        def user
    
        def beforeInterceptor = {
            user = request.user
        }
    
        def index = { 
            render text:"index: ${user}"        
        }
    
        def test = {
            render text:"test: ${user}"         
        }
    }
    

    【讨论】:

      【解决方案2】:

      我认为每次都将用户对象插入到请求对象中通常不是一个好主意:

      请求的生命周期非常短,因此您最终可能会在每个 http-request 中往返于缓存,甚至更糟地访问数据库以检索对象,您甚至可能不需要这些对象,并且之后会立即将其删除。因此,如果必须,最好将整个对象存储在会话中,而不仅仅是 id。

      一般来说,我建议您编写一个 AuthenticationService,其中包含在用户通过身份验证时返回 true 的方法 isLoggedIn() 和返回此对象的方法 getLoggedInUser()

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

      然后,如果未通过身份验证,则使用过滤器进行重定向,并且可能使用拦截器来存储本地引用 user = authenticationService.loggedInUser。但我也不认为这是最好的方法。我建议您为 src/groovy 中的所有控制器创建一个抽象的 AuthenticationAwareController 作为基类,并且有像 user 这样的便捷方法

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

      这样,您以后可以改变主意,按照自己的喜好存储用户,而不必更改代码。此外,您还受益于 Hibernate 中的缓存,它在不同会话之间共享已检索到的用户对象实例,因此避免了数据库往返。

      您仍然应该检查检索到的用户对象的有效性或抛出AuthenticationException,以防检索不成功。 (可能类似于AuthenticationService.getLoggedInUser(failOnError = false)。)

      您甚至可以将此 Service/ControllerBase 制作为一个小插件,以便在每个应用程序上重复使用,或者直接使用 spring 安全插件... ;-)

      【讨论】:

        【解决方案3】:

        我认为你可以做到这一点,但这真的值得吗?在我看来,您唯一的优势是输入“user”而不是“request.user”。收获不大。无论如何,我认为您可以按照用户指南的“12.7 在运行时添加动态方法”中的说明进行操作。我认为如果您创建了一个动态方法“getUser() {return request.user}”,Groovy JavaBeans getter/setter 访问将允许您以您想要的方式简单地引用“用户”。

        如果您确实添加了动态方法,您可能希望跳过过滤器并在动态方法中完成所有操作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-09-06
          • 1970-01-01
          • 2017-09-20
          • 2015-10-15
          • 1970-01-01
          • 2017-09-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多