Espressioni regolari e validazione di nickname e password con Spring Boot 2

di il
4 risposte

Espressioni regolari e validazione di nickname e password con Spring Boot 2

Ho questa classe di validazione che fa il suo lavoro ma ho difficoltà ad implementare le espressioni regolari.
@Component
public class ValidazioneDatiFormRegistrazione implements Validator {
    @Autowired
    private UtenteRepository utenteRepository;
    @Override
    public boolean supports(Class<?> clazz) {
        return clazz == UtenteForm.class;
    }
    @Override
    public void validate(Object target, Errors errors) {
        UtenteForm appUserForm = (UtenteForm) target;
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "NotEmpty.appUserForm.userName");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "NotEmpty.appUserForm.password");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confirmPassword", "NotEmpty.appUserForm.confirmPassword");
        if (!errors.hasFieldErrors("userName")) {
            Utente dbUser = new Utente();
            String nomeUtenteScelto = appUserForm.getUserName();
            String passwordScelta = appUserForm.getPassword();
            if (nomeUtenteScelto.length() < 1) {
                errors.rejectValue("userName", "NomeUtente.appUserForm.userName");
            }
            if (passwordScelta.length() < 10) {
                errors.rejectValue("password", "Password.appUserForm.userName");
            }
            try {
                dbUser = utenteRepository.trovaUtente(appUserForm.getUserName());
            } catch(Exception e) {
                dbUser = null;
            }
            if (dbUser != null) {
                errors.rejectValue("userName", "Duplicate.appUserForm.userName");
            }
        }
        if (!errors.hasErrors()) {
            if (!appUserForm.getConfirmPassword().equals(appUserForm.getPassword())) {
                errors.rejectValue("confirmPassword", "Match.appUserForm.confirmPassword");
            }
        }
    }
}
Nel nome utente avrei preferito togliere i caratteri speciali che non vengono usati per scrivere un nome italiano o estero (~,},æ,¼, ecc...). Stavo valutando di permettere l'uso dello spazio ma su questo punto vi chiedo un consiglio sulla base della vostra esperienza.
Ho provato a scrivere questo:
if (!(Pattern.matches("[a-zA-Z0-9]+", nomeUtenteScelto) == false && nomeUtenteScelto.length() > 5)) {
     errors.rejectValue("password", "Password.appUserForm.userName");
}
ma non funziona, per esempio ~ può essere aggiunto. Elencare tutte le lettere che possono essere usate è scomodo e pericoloso anche perché potrei dimenticarmene qualcuna. Su Spring Boot 2 per caso esiste qualcosa che può venirmi utile?
Per quanto riguarda la password il problema è un tantino più complicato perché vorrei che avesse queste specifiche:
1) è lunga almeno 10 caratteri
2) possiede lettere maiuscole
3) possiede lettere minuscole
4) possiede numeri
5) contiene simboli non alfabetici come ad esempio: ` ! " ? $ ? % ^ & * ( ) _ - + = { [ } ] : ; @ ' ~ # | \ < , > . ? /
Inoltre ho letto che le espressioni regolari non funzionano al 100% ma solo al 99.99% perché alcuni caratteri sfuggono come ad esempio il #, stavo cercando il link della pagina ma non lo trovo più.

4 Risposte

  • Re: Espressioni regolari e validazione di nickname e password con Spring Boot 2

    Forse la condizione sulla lunghezza doveva essere:
    
    if (!Pattern.matches("[a-zA-Z0-9]+", nomeUtenteScelto) || (nomeUtenteScelto.length() < 5)) {
       ...   // Errore
    }
    
    Perchè fare una cosa contorta come confrontare un valore booleano con false, metterlo in AND con un altra espressione booleana per poi invertire il tutto con un NOT? Cerchiamo di sfruttare la short-circuit dove possibile...
  • Re: Espressioni regolari e validazione di nickname e password con Spring Boot 2

    iBaffiPro ha scritto:


    ma non funziona, per esempio ~ può essere aggiunto.
    In una "classe di caratteri" (sintassi [ ] ) se si vuole esprimere letteralmente il - (trattino) va messo o all'inizio o al fondo o in mezzo MA escaped ( \- ; \\- in stringa literal ). Altrimenti funge da "range".

    iBaffiPro ha scritto:


    Su Spring Boot 2 per caso esiste qualcosa che può venirmi utile?
    No, direi.

    iBaffiPro ha scritto:


    Per quanto riguarda la password il problema è un tantino più complicato perché vorrei che avesse queste specifiche:
    1) è lunga almeno 10 caratteri
    2) possiede lettere maiuscole
    3) possiede lettere minuscole
    4) possiede numeri
    5) contiene simboli non alfabetici come ad esempio: ` ! " ? $ ? % ^ & * ( ) _ - + = { [ } ] : ; @ ' ~ # | \ < , > . ? /
    Tutto questo è parecchio complicato(/impossibile) con una singola espressione regolare, specialmente se ti aspetti che 2) 3) 4) 5) siano tutti "veri" e che possano essere (come è logico) in "qualunque posizione".
    Meglio fare più regex o altrimenti ricorrere alla classica logica imperativa.

    iBaffiPro ha scritto:


    Inoltre ho letto che le espressioni regolari non funzionano al 100% ma solo al 99.99%
    Falso (per quanto ne so).

    iBaffiPro ha scritto:


    perché alcuni caratteri sfuggono come ad esempio il #
    Il # è un carattere come un altro, non è nemmeno un carattere "speciale" per le regex quindi non deve nemmeno essere escaped.
  • Re: Espressioni regolari e validazione di nickname e password con Spring Boot 2

    Grazie per il tuo supporto. Ho creato un metodo ad hoc per la password perché in effetti con le espressioni regolari sarebbe stato impossibile, troppo complesso o semplicemente avrebbe dato origine ad un codice poco leggibile/editabile.
    L’unico problema che ho incontrato e nel definire il carattere speciale nella password.
    Ti faccio subito un esempio.
    Se mi chiamassi Torbjørn e volessi iscrivermi all’applicazione il mio nome non verrebbe accettato a causa di questo codice:
                if (!Pattern.matches("[a-zA-Zàèéìòùç0-9 ]+", nomeUtenteScelto) || (nomeUtenteScelto.length() < 5)) {
                    errors.rejectValue("userName", "NomeUtente.appUserForm.userName");
                }
    Inoltre, nella verifica della password se uso queste espressioni regolari:
                    espressioni_regolari[0] = "[a-zàèéìòùç]+";
                    espressioni_regolari[1] = "[A-ZÀÈÉÌÒÙÇ]+";
                    espressioni_regolari[2] = "[0-9]+";
                    espressioni_regolari[3] = "[^a-zàèéìòùçA-ZÀÈÉÌÒÙÇ0-9]+";
    per verificare l’esistenza di alcuni caratteri specifici, il carattere ø viene inteso come speciale ma nella lingua questo carattere non lo è.
    Non esiste una stringa o una variabile in Spring Boot contenente tutte le lettere che possono essere usate in questo mondo, anche cinese, arabo, ecc…?
    Stavo anche pensando se le char in java sono ordinate in qualche modo intelligente ma dopo aver scritto un ciclo for ho appurato di no.
    Come scriverebbe un programmatore serio quelle espressioni regolari nel caso volesse fare un codice multilingua serio e senza reinventare la ruota?
    Siamo sicuri che in Spring Boot o qualche dipendenza non esista proprio nulla che possa venirmi in aiuto?
    In merito alla validità delle espressioni regolari ho trovato questo:
    https://lorenzoneri.com/come-validare-une-mail-con-le-espressioni-regolari/
    ma non capisco la complicazione di quel codice è perché dice che non è possibile scrivere un’espressione regolare funzionante al 100%.
  • Re: Espressioni regolari e validazione di nickname e password con Spring Boot 2

    iBaffiPro ha scritto:


    Se mi chiamassi Torbjørn e volessi iscrivermi all’applicazione il mio nome non verrebbe accettato a causa di questo codice:
                if (!Pattern.matches("[a-zA-Zàèéìòùç0-9 ]+", nomeUtenteScelto) || (nomeUtenteScelto.length() < 5)) {
                    errors.rejectValue("userName", "NomeUtente.appUserForm.userName");
                }
    No. Ha senso mettere una serie di caratteri così (es. "àèìòù" ecc...) SOLO se sono in numero ragionevolmente limitato perché bastano solo quelli.
    Ma tanto per darti una idea, nel Java 16 che è allineato al Unicode 13.0, ci sono 283440 code-point definiti di cui 131241 sono considerati "lettere".

    Quindi se ti basta considerare TUTTE le lettere come inteso nello standard Unicode, nelle regex ci sono diversi modi per descriverlo molto in generale:

    \p{L} (L è la Category nel Unicode per Letter)
    \p{isLetter} (come binary property)

    EDIT: anzi, forse la category Letter è un po' troppo solo per dei nomi utente, perché L contempla anche gli Lo (other letter) che sono es. ª º ? e altri. Potrebbe bastare l'insieme delle categorie Ll (lowercase) e Lu (uppercase), quindi \p{Ll} e \p{Lu}

    Queste cose sono spiegate nella documentazione di Pattern.
    E se vuoi vedere le categorie: https://www.compart.com/en/unicode/categor

    iBaffiPro ha scritto:


    il carattere ø viene inteso come speciale
    No, il ø non è speciale. Nelle regex un carattere è "speciale" quando normalmente NON rappresenta sé stesso ma un concetto più particolare/ampio. Tipo il punto "." che descrive "un qualunque carattere". Se vuoi che il punto rappresenti esattamente sé stesso, lo devi escapare (brutto dirlo in italiano, meglio escaped), ovvero \. che in una stringa literal nel sorgente vuol dire raddoppiare il backslash ovvero "\\."

    Il ø matcha esattamente sé stesso (prova: stringa "aeiøu" e fai un find() con pattern "ø", lo trovi), quindi non è "speciale" per le regex.

    iBaffiPro ha scritto:


    Non esiste una stringa o una variabile in Spring Boot contenente tutte le lettere che possono essere usate in questo mondo, anche cinese, arabo, ecc…?
    In Spring Boot dubito. Scusa ma guardare la documentazione di Pattern e documentarsi un po' sul Unicode?

    iBaffiPro ha scritto:


    Stavo anche pensando se le char in java sono ordinate in qualche modo intelligente
    Cosa intendi per "ordinate in qualche modo intelligente"?? Java si basa sullo standard Unicode, che contempla centinaia di migliaia di caratteri. E i char in Java vengono confrontati in base al codice Unicode del carattere.

    iBaffiPro ha scritto:


    Come scriverebbe un programmatore serio quelle espressioni regolari nel caso volesse fare un codice multilingua serio e senza reinventare la ruota?
    L'ho detto brevemente prima, basta documentarsi su regex/Unicode.
Devi accedere o registrarti per scrivere nel forum
4 risposte