Grails 2.5如何使用服务内部验证器验证域对象密码



我们有一个简单的操作符对象,它使用spring安全性对密码进行编码:

class Operator
   transient springSecurityService
   def siteService
   String username
   Site   site
   String password
   def beforeInsert() {
        encodePassword()
   }
   def beforeUpdate() {
       if (isDirty('password')) {
           encodePassword()
       }
    }
   protected void encodePassword() {
       password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
   }

现在我们要验证密码是否与运行时定义的regexp匹配。操作符可以通过UI(即标准CRUD表单)创建。每个站点都有不同的regexp。事实上,密码会被一个编码的密码覆盖,而我们不应该测试它,这使得它更具挑战性。

尝试1:在encodePassword()中进行验证:

def beforeInsert() {
  protected void encodePassword() {
    String regexp = siteService.getInheritedValue(site, "operatorPasswordRegexp")
     if (!password.matches(regexp) {
         thrown new RuntimeException "invalid password format"
     }
    password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
  }
}

这部分有效,因为它阻止创建与运行时发现的regexp不匹配的密码。问题是,当我们希望操作员编辑表单用友好的验证消息突出显示密码字段时,它会抛出一个异常,生成一个500错误页面。

尝试二,使用自定义验证器

static constraints = {
password    password: true, blank:false, validator: { val, obj ->
        if (obj.isDirty(val)) {
           return true
        }
        String regexp = obj.siteService.getInheritedValue(obj.operates, "operatorPasswordRegexp")
        if (regexp != null && regexp != "") {
            return val.matches(regexp)
        }
        return true
    }

这似乎可以工作,但保存总是默默地失败。我花了一些时间才明白为什么——当你这样做的时候:

operator.password="valid1"
opertor.save(failonError:true)  

不抛出错误。即使您删除了failonError,并检查返回值,它始终为空(没有错误)。但是它不保存操作符。

问题在于beforeInsert将密码更新为一个编码版本,而这个版本当然没有通过验证器(也不应该通过),验证器此时说不,并且保存无声地失败。也就是说,对于单个保存,验证器被调用两次。

问题是,我如何得到beforeInsert()代码不调用验证器,或验证器忽略从beforeInsert调用?

您可以使用这两种方法来完成任务。

1:在encodePassword()中进行验证:不抛出异常,而是向实例添加错误。我认为你的encodePassword()函数是在相同的域中,所以用this.errors得到与它相关的错误对象。例:

this.errors.rejectValue("password", "user.password.pattern.error")

有不同的rejectValue方法,这个方法接受字段名和消息中定义的消息代码。属性文件。

2:自定义验证器:

isDirty()不是一个静态方法,使用自定义验证器中提供的obj调用它。isDirty()接受要检查是否脏的属性名,而不是它的值。

obj.isDirty(PropertyName)

constraints是一个静态块,它不能直接访问你的服务。你需要使用静态上下文注入你的服务。

static SiteService siteService;

我建议使用自定义验证器。

相关内容

  • 没有找到相关文章

最新更新