Hibernate验证器:@Email接受要求@ stackoverflow有效吗?

jac*_*ack 49 validation hibernate spring-mvc hibernate-validator

我正在使用@Email注释来验证电子邮件地址.我遇到的问题是它接受像ask@stackoverflow有效的电子邮件地址这样的东西.我想这是因为他们想要支持内部网地址,但我似乎找不到一个标志,所以它检查扩展.

我是否真的需要切换到@Pattern(以及任何灵活的电子邮件模式的建议)或者我错过了什么?

小智 50

您还可以使用约束合成作为解决方法.在下面的示例中,我依靠@Email验证器进行主验证,并添加@Pattern验证器以确保地址的形式为x@y.z(我不建议仅使用@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
public @interface ExtendedEmailValidator {
    String message() default "Please provide a valid email address";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
Run Code Online (Sandbox Code Playgroud)

  • **警告**:该正则表达式可用于 [ReDoS](https://en.wikipedia.org/wiki/ReDoS)。如果您[尝试插入一长串@](https://regex101.com/r/rn4Hz1/1),则会导致超时。发生这种情况是因为 `.+` 也匹配 `@`。这个应该更安全:`[^@]+@[^@]+\.[^@.]+` (2认同)

axt*_*avt 33

实际上,@EmailHibernate Validator在内部使用regexp.您可以根据正则表达式轻松定义自己的约束,并根据需要进行修改(请注意+结尾处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
                    + ")$";
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,但我有点惊讶我需要为看似真正常见的要求制作一个自定义验证器.我期待这种事情的旗帜. (17认同)

小智 17

实际上验证电子邮件地址真的很复杂.无法验证电子邮件地址在语法上是否正确并且在注释中寻址预期收件人.该@Email注释是一个有用的最小的支票,不从假阴性的问题的困扰.

验证的下一步应该是发送一封电子邮件,其中包含用户必须完成的挑战,以确定用户是否可以访问该电子邮件地址.

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


Sla*_*hin 15

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

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

@Email(regexp = ".+@.+\\..+")
private String email;
Run Code Online (Sandbox Code Playgroud)


Nei*_*gan 6

这是使用 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

以及注释:

@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();
    }
}
Run Code Online (Sandbox Code Playgroud)