web-dev-qa-db-fra.com

Hibernate validator: @Email accepte-t-il ask @ stackoverflow comme valide?

J'utilise l'annotation @Email pour valider une adresse électronique .Le problème que je rencontre est qu'il accepte des éléments tels que ask@stackoverflow comme adresse électronique valide . Je suppose que c'est parce qu'ils veulent supporte les adresses intranet, mais je n'arrive pas à trouver un drapeau, donc il vérifie la présence d'une extension.

Dois-je vraiment passer à @Pattern (et des recommandations pour un modèle de courrier électronique flexible) ou ai-je oublié quelque chose?

47
jack

En fait, @Email de Hibernate Validator utilise regexp en interne . Vous pouvez facilement définir votre propre contrainte basée sur cette expression rationnelle, modifiée selon vos besoins (notez le + à la fin de 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
                    + ")$";
}
33
axtavt

Vous pouvez également utiliser composition de contraintes comme solution de contournement. Dans l'exemple ci-dessous, je m'appuie sur le validateur @Email pour effectuer la validation principale et ajouter un validateur @Pattern pour m'assurer que l'adresse est sous la forme [email protected] (je ne recommande pas d'utiliser uniquement le @Pattern ci-dessous pour la validation régulière par courrier électronique). 

@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 {};
}
46
Matt

En réalité, la validation des adresses e-mail est vraiment complexe. Il n'est pas possible de valider qu'une adresse électronique est syntaxiquement correcte et adresse le destinataire voulu dans une annotation. L'annotation @Email est une vérification minimale utile qui ne souffre pas du problème des faux négatifs.

La prochaine étape de la validation devrait consister à envoyer un courrier électronique avec un défi que l’utilisateur doit terminer pour établir qu’il a accès à l’adresse électronique.

Il est préférable d’accepter quelques faux positifs à l’étape 1 et de laisser passer des adresses électroniques non valides plutôt que de rejeter des utilisateurs valides. Si vous souhaitez appliquer des règles supplémentaires, vous pouvez ajouter davantage de contrôles, mais faites très attention à ce que vous supposez être une adresse de messagerie valide. Par exemple, rien dans les RFC n'indique que i@nl serait invalide, car nl est un domaine de premier niveau enregistré.

14
David

Voici un validateur de courrier électronique javax.validation utilisant Apache Commons Validator

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);
    }
}

Et l'annotation:

@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();
    }
}
3
Neil McGuigan

La solution de composition de contrainte ne fonctionne pas. Lorsque Email est utilisé avec Pattern, la regex Email est conservée avec une priorité supérieure. Je pense que cela est dû au fait que l'annotation Email remplace quelques attributs de modèle, à savoir flags et regexp (la clé ici). Si je supprime @Email, l'expression régulière @Pattern s'appliquera uniquement lors des validations. 

/**
 * @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 { };
0
user1048931

Évidemment, je suis en retard au Parti, je réponds néanmoins à cette question, 

Pourquoi ne pouvons-nous pas utiliser l'annotation @Pattern avec des expressions régulières dans notre classe de validation comme celle-ci 

public Class Sigunup {

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

}

C'est plus facile. 

0
user2245151

Si vous essayez la solution ci-dessus https://stackoverflow.com/a/12515543/258544 ajoutez le @ReportAsSingleViolation dans la définition de l'annotation, vous éviterez ainsi le message de validation (un de @Email et un de @Pattern) car il s’agit d’une annotation composée: 

@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

De @interface ReportAsSingleViolation javax.validation: validation-api: 1.1.0.Final) définition d'annotation: "... L'évaluation des contraintes composées s'arrête à la première validation Erreur au cas où la contrainte de composition est annotée avec ReportAsSingleViolation "

0
Francisco Quiñones

Vous pouvez utiliser Email regexp, en vous assurant également que la validation n'échoue pas lorsque l'email est vide.

@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 {};
}
0
Davithbul