【问题标题】:Hibernate validator: @Email accepts ask@stackoverflow as valid?Hibernate 验证器:@Email 接受 ask@stackoverflow 是否有效?
【发布时间】:2022-01-22 22:51:31
【问题描述】:

我正在使用@Email 注释来验证电子邮件地址。 我遇到的问题是它接受ask@stackoverflow 之类的东西作为有效的电子邮件地址。 我猜这是因为他们想支持 Intranet 地址,但我似乎找不到标志,所以它确实检查了扩展名。

我真的需要切换到@Pattern(以及任何关于灵活电子邮件模式的建议)还是我遗漏了什么?

【问题讨论】:

  • 你指的是org.hibernate.validator.Email吗?
  • org.hibernate.validator.constraints.Email;和版本 4.0.2.GA
  • 域中不带点的电子邮件实际上是有效的:isemail.info/about
  • 请不要对电子邮件使用正则表达式验证,只需检查内部是否有@ 并尝试在那里发送激活电子邮件。我们需要的唯一真正的验证是对我们的服务感兴趣的人是否可以点击附加的链接。
  • @chrylis 感谢您的贡献。是的,你是对的。在我的系统中,它被认为是无效的电子邮件,因此被拒绝。

标签: hibernate validation spring-mvc hibernate-validator


【解决方案1】:

您也可以使用constraint composition 作为解决方法。在下面的示例中,我依靠@Email 验证器进行主要验证,并添加了@Pattern 验证器以确保地址为x@y.z 的形式(我不建议只使用@987654327 @ 下面用于常规电子邮件验证)

@Email(message="Please provide a valid email address")
@Pattern(regexp=".+@.+\\..+", message="Please provide a valid email address")
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface ExtendedEmailValidator {
    String message() default "Please provide a valid email address";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

【讨论】:

  • 这确实是更好的解决方案
  • 警告:该正则表达式可用于ReDoS。如果你try to insert a long sequence of @ 它会导致超时。这是因为.+ 也匹配@。这个应该更安全:[^@]+@[^@]+\.[^@.]+
【解决方案2】:

实际上,@Email 来自 Hibernate Validator uses regexp internally。您可以根据该正则表达式轻松定义自己的约束,并根据需要进行修改(注意DOMAIN 末尾的+):

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Pattern(regexp = Constants.PATTERN, flags = Pattern.Flag.CASE_INSENSITIVE)
public @interface EmailWithTld {
    String message() default "Wrong email";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}

interface Constants {
    static final String ATOM = "[a-z0-9!#$%&'*+/=?^_`{|}~-]";
    static final String DOMAIN = "(" + ATOM + "+(\\." + ATOM + "+)+";
    static final String IP_DOMAIN = "\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\]";

    static final String PATTERN =
            "^" + ATOM + "+(\\." + ATOM + "+)*@"
                    + DOMAIN
                    + "|"
                    + IP_DOMAIN
                    + ")$";
}

【讨论】:

  • 是的,但我有点惊讶我需要为看起来很常见的需求制作一个自定义验证器。我希望这种事情有一个标志。
  • @Matt 解决方案要简单得多,因为它只在注释中添加一行
  • 此答案中的链接已损坏。
  • 添加到Patternmessage - message="Please provide a valid email address"
  • 忽略it have to be ..".+@.+\..+"
【解决方案3】:

虽然您仍然可以实现自己的验证器或编写自定义验证器来聚合 @Email@Pattern,但您不必再这样做了!

在最近的一个版本中(它肯定存在于 hibernate-validator 6.0.x 中),@Email 具有新的regexp 属性,即“注释元素必须匹配的附加正则表达式”。换句话说,这是一种新方法:

@Email(regexp = ".+@.+\\..+")
private String email;

【讨论】:

    【解决方案4】:

    实际上验证电子邮件地址非常复杂。无法验证电子邮件地址在语法上是否正确并在注释中针对预期的收件人。 @Email 注释是一种有用的最小检查,不会出现误报问题。

    验证的下一步应该是发送一封电子邮件,其中包含用户必须完成的挑战才能确定用户有权访问该电子邮件地址。

    最好在步骤 1 中接受一些误报并允许一些无效的电子邮件地址通过,而不是拒绝有效的用户。如果您想应用额外的规则,您可以添加更多检查,但要非常小心您认为是有效电子邮件地址的要求。例如,RFC 中没有任何内容规定 i@nl 无效,因为 nl 是注册的国家顶级域。

    【讨论】:

      【解决方案5】:

      这是一个使用 Apache Commons Validator 的 javax.validation 电子邮件验证器

      public class CommonsEmailValidator implements ConstraintValidator<Email, String> {
      
          private static final boolean ALLOW_LOCAL = false;
          private EmailValidator realValidator = EmailValidator.getInstance(ALLOW_LOCAL);
      
          @Override
          public void initialize(Email email) {
      
          }
      
          @Override
          public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
              if( s == null ) return true;
              return realValidator.isValid(s);
          }
      }
      

      还有注解:

      @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE,  ElementType.CONSTRUCTOR, ElementType.PARAMETER})
      @Retention(RetentionPolicy.RUNTIME)
      @Constraint(validatedBy = {CommonsEmailValidator.class})
      @Documented
      @ReportAsSingleViolation
      public @interface Email {
      
          String message() default "{org.hibernate.validator.constraints.Email.message}";
      
          Class<?>[] groups() default {};
      
          Class<? extends Payload>[] payload() default {};
      
          @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          public @interface List {
              Email[] value();
          }
      }
      

      【讨论】:

        【解决方案6】:

        显然我迟到了,我还在回答这个问题,

        为什么我们不能像这样在我们的验证类中使用带有正则表达式的@Pattern注解

        public Class Sigunup {
        
            @NotNull
            @NotEmpty
            @Pattern((regexp="[A-Za-z0-9._%-+]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}")
            private String email;
        
        }
        

        它更容易。

        【讨论】:

        • ... 错了。 "test@myexample..loc" 对这个正则表达式有效。
        • 你能详细说明一下吗?
        • 域部分中的双点不被识别为错误。此外,元音变音域和更多有效的电子邮件地址模式未被检测为有效。因此,最好让验证由特殊库执行,例如 Apache Commons EmailValidator。请参阅 gist.github.com/robertoschwald/ce23c8c23ebd5b93fc3f60c150e35cea 如何使用 Hibernate 来做到这一点。
        【解决方案7】:

        如果您要尝试上述解决方案https://stackoverflow.com/a/12515543/258544,请在注释定义中添加@ReportAsSingleViolation,这样您将避免验证消息(一条来自@Email,一条来自@Pattern),因为它是组合注释:

            @Email(message="Please provide a valid email address")
            @Pattern(regexp=".+@.+\\..+", message="Please provide a valid email address")
            @Target( { METHOD, FIELD, ANNOTATION_TYPE })
            @Retention(RUNTIME)
            @Constraint(validatedBy = {})
            @Documented
            @ReportAsSingleViolation
        

        来自@interface ReportAsSingleViolationjavax.validation:validation-api:1.1.0.Final) 注释定义: “...组合约束的评估在第一次验证时停止 使用 ReportAsSingleViolation 注释组合约束时出错”

        【讨论】:

          【解决方案8】:

          您可以使用电子邮件正则表达式,同时确保电子邮件为空时验证不会失败。

          @Email(regexp = ".+@.+\\..+|")
          @Target({METHOD, FIELD, ANNOTATION_TYPE})
          @Retention(RUNTIME)
          @Constraint(validatedBy = {})
          @Documented
          public @interface ExtendedEmail {
          
            @OverridesAttribute(constraint = Email.class, name = "message")
            String message() default "{javax.validation.constraints.Email.message}";
          
            @OverridesAttribute(constraint = Email.class, name = "groups")
            Class<?>[] groups() default {};
          
            @OverridesAttribute(constraint = Email.class, name = "payload")
            Class<? extends Payload>[] payload() default {};
          }
          

          【讨论】:

            【解决方案9】:

            约束组合解决方案不起作用。当电子邮件与 Pattern 结合使用时,电子邮件正则表达式具有更高的优先级。我相信这是因为电子邮件注释覆盖了一些模式属性,即标志和正则表达式(这里的关键)如果我删除@Email,那么只有@Pattern 正则表达式才会应用于验证。

            /**
             * @return an additional regular expression the annotated string must match. The default is any string ('.*')
             */
            @OverridesAttribute(constraint = Pattern.class, name = "regexp") String regexp() default ".*";
            
            /**
             * @return used in combination with {@link #regexp()} in order to specify a regular expression option
             */
            @OverridesAttribute(constraint = Pattern.class, name = "flags") Pattern.Flag[] flags() default { };
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2022-10-22
              • 2017-04-07
              • 1970-01-01
              • 1970-01-01
              • 2018-11-18
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多