IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Java Discussion :

Changer les messages d'erreur, best practice


Sujet :

Spring Java

  1. #1
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut Changer les messages d'erreur, best practice
    Bonjour à tous,

    Dans une Webapp, c'est quoi les best practices pour changer les messages d'erreur de spring security 3.x ?

    Par exemple, si je prend le message identifié par la clé "AbstractUserDetailsAuthenticationProvider.badCredentials" dans le fichier "messages_fr.properties" qu'on trouve dans le jar de spring secu. C'est quoi le mieux ?

    Merci d'avance
    Th.

  2. #2
    Membre confirmé
    Avatar de Khaled.Noordin
    Homme Profil pro
    Inscrit en
    Janvier 2005
    Messages
    354
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 354
    Points : 497
    Points
    497
    Billets dans le blog
    1
    Par défaut
    Salut Thierry,
    perso pour changer les messages selon besoin, j'ai cherché a récupérer la clé du message, que j'ai ensuite ajouté à mon fichier properties d'internationalisation, voici un petit exemple(c'est en groovy et avec jsf 2 et avec omnifaces)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    package site.controller.listener.spring
     
    import org.omnifaces.eventlistener.DefaultPhaseListener
    import org.springframework.security.authentication.*
    import org.springframework.security.core.userdetails.UsernameNotFoundException
    import org.springframework.security.web.WebAttributes
    import site.service.config.IAuthorizationConfigService
    import site.service.config.II18nConfigService
     
    import javax.faces.application.FacesMessage
    import javax.faces.context.ExternalContext
    import javax.faces.context.FacesContext
    import javax.faces.event.PhaseEvent
    import javax.faces.event.PhaseId
     
    class AuthenticationPhaseListener extends DefaultPhaseListener {
     
        AuthenticationPhaseListener() { super(PhaseId.RENDER_RESPONSE) }
     
        @Override
        void beforePhase(PhaseEvent event) {
            FacesContext context = event.facesContext
            ExternalContext externalContext = event.facesContext.externalContext
            ResourceBundle bundle = ResourceBundle.getBundle(
                    II18nConfigService.BUNDLE_BASE_NAME_VALUE,
                    context.viewRoot.locale,
                    Thread.currentThread().contextClassLoader)
            Exception e = externalContext.sessionMap
                    .get(WebAttributes
                    .AUTHENTICATION_EXCEPTION) as Exception
     
            if (e instanceof UsernameNotFoundException) {
                //comment j'ai recuperé la clef
                println "\n\n${e.message}\n\n"
     
                externalContext.sessionMap.put WebAttributes.AUTHENTICATION_EXCEPTION, null
                context.addMessage IAuthorizationConfigService.USERNAME_FIELD_ID,
                        new FacesMessage(
                                severity: FacesMessage.SEVERITY_ERROR,
                                summary: bundle.getString(e.message))
            }
     
            if (e instanceof BadCredentialsException) {
                externalContext.sessionMap.put WebAttributes.AUTHENTICATION_EXCEPTION, null
                context.addMessage IAuthorizationConfigService.PASSWORD_FIELD_ID,
                        new FacesMessage(
                                severity: FacesMessage.SEVERITY_ERROR,
                                summary: bundle.getString(e.message))
            }
     
            if (e instanceof DisabledException) {
                externalContext.sessionMap.put WebAttributes.AUTHENTICATION_EXCEPTION, null
                context.addMessage IAuthorizationConfigService.USERNAME_FIELD_ID,
                        new FacesMessage(
                                severity: FacesMessage.SEVERITY_ERROR,
                                summary: bundle.getString(e.message))
            }
     
            if (e instanceof AccountExpiredException) {
                externalContext.sessionMap.put WebAttributes.AUTHENTICATION_EXCEPTION, null
                context.addMessage IAuthorizationConfigService.USERNAME_FIELD_ID,
                        new FacesMessage(
                                severity: FacesMessage.SEVERITY_ERROR,
                                summary: bundle.getString(e.message))
            }
     
            if (e instanceof LockedException) {
                externalContext.sessionMap.put WebAttributes.AUTHENTICATION_EXCEPTION, null
                context.addMessage IAuthorizationConfigService.USERNAME_FIELD_ID,
                        new FacesMessage(
                                severity: FacesMessage.SEVERITY_ERROR,
                                summary: bundle.getString(e.message))
            }
     
            if (e instanceof CredentialsExpiredException) {
                externalContext.sessionMap.put WebAttributes.AUTHENTICATION_EXCEPTION, null
                context.addMessage IAuthorizationConfigService.PASSWORD_FIELD_ID,
                        new FacesMessage(
                                severity: FacesMessage.SEVERITY_ERROR,
                                summary: bundle.getString(e.message))
            }
        }
    }
    ici j'ai essayé un username qui n'existe pas et à l'output j'ai eu : authentication.UsernameNotFoundException.message la clef que je cherchais
    et ainsi de suite pour les autres du coup j'ai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    authentication.UsernameNotFoundException.message=pseudo ou courriel n'existe pas
    authentication.BadCredentialsException.message=mauvais mot de passe
    authentication.DisabledException.message=ce compte n'est pas actif
    authentication.AccountExpiredException.message=compte utilisateur expir\u00c3\u00a9
    authentication.LockedException.message=compte utilisateur v\u00c3\u00a9rouill\u00c3\u00a9
    authentication.CredentialsExpiredException.message=mot de passe expir\u00c3\u00a9
    apres je prétend pas que c'est une best practice c'est juste ma technique, qui marche.

  3. #3
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    Hummm

    Je ne comprend pas à quoi sert ton AuthenticationPhaseListener :-(

    Dans mon bundle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    login.error.failed=TODO {0}
    login.error.badCredentials=Les identifiants (login et/ou mot de passe) ne sont pas bons.
    Et dans ma page :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <h:outputFormat value="#{login_messages['login.error.failed']}">
    	<f:param value="#{sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}" />
    </h:outputFormat>

    Dans spring-security-core-3.1.0.jar, j'avais trouvé ça :

    AbstractUserDetailsAuthenticationProvider.badCredentials=Les cr\u00E9ances sont erron\u00E9es
    Même en le mettant aussi dans mon bundle avec mon propre message, ça ne change rien :-(

  4. #4
    Membre confirmé
    Avatar de Khaled.Noordin
    Homme Profil pro
    Inscrit en
    Janvier 2005
    Messages
    354
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 354
    Points : 497
    Points
    497
    Billets dans le blog
    1
    Par défaut
    Salut,
    tu as Spring security d'un coté et JSF de l'autre, spring security travail avec des filtres de requet successif, donc pour faire simple depuis jsf j'appel un request dispatcher vers l'url d'authentification de spring security qui lance ses traitement, en retour spring renvoi une erreur qui est intercepté par le phaselistener, ou sinon passe la main à l'authenticationsuccessfulhandler qui permet à JSF de faire sa redirection vers la ou on lui demande, dans mon cas je l'ai intégré à spring webflow a qui j'ai dit revient a l'url précédent l'authentification.
    Et donc je pense que si tu arrive pas à intercepter le message c'est justement car le tu le prend tard dans le cycle de vie de jsf c'est justement a cela que sert mon phaselistener qui se place en before de la phase render response, du coup peu importe ton override de message c'est spring qui met ce que lui veut dans le message.

    voila mon controller d'authentification
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    package site.controller.faces
     
    import org.hibernate.validator.constraints.NotBlank
     
    import javax.faces.context.ExternalContext
    import javax.faces.context.FacesContext
    import javax.inject.Named
    import javax.servlet.RequestDispatcher
    import javax.servlet.ServletRequest
    import javax.servlet.ServletResponse
     
    @Named("authenticationController")
    class AuthenticationController {
     
     
        @NotBlank
        String username
        @NotBlank
        String password
        Boolean rememberMe
     
        void clearAuthenticateFormData() {
            username = null
            password = null
            rememberMe = null
        }
     
        static String authenticate() {
            FacesContext context = FacesContext.currentInstance
            ExternalContext externalContext = FacesContext.currentInstance.externalContext
            RequestDispatcher dispatcher = (externalContext.request as ServletRequest)
                    .getRequestDispatcher("/j_spring_security_check")
            dispatcher.forward externalContext.request as ServletRequest,
                    externalContext.response as ServletResponse
            context.responseComplete()
            return null
        }
    }
    sans oublier ça dans le web.xml
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        <filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
            <dispatcher>FORWARD</dispatcher>
            <dispatcher>REQUEST</dispatcher>
        </filter-mapping>

  5. #5
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    La partie dans le web.xml, je l'ai déjà, forcément ;-)

    Sinon, dans ma conf, j'ai mis ça :

    security-app-context.xml
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    <beans:bean id="contextSource"
    	class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
    	<beans:constructor-arg index="0" value="${ldap.url}" />
    	<beans:property name="userDn" value="${ldap.userDn}" />
    	<beans:property name="password" value="${ldap.password}" />
    </beans:bean>
     
    <beans:bean id="ldapUserSearch"
    	class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
    	<beans:constructor-arg index="0" value="ou=people" /> 
    	<beans:constructor-arg index="1" value="(uid={0})" /> 	
    	<beans:constructor-arg index="2" ref="contextSource" />
    	<beans:property name="searchSubtree" value="true" />
    </beans:bean>
     
    <beans:bean id="monprojetAuthoritiesPopulator"
    	class="com.masociete.monprojet.web.security.MonprojetAuthoritiesPopulator" />
    <beans:bean id="extragroupUserDetailsContextMapper"
    	class="com.masociete.monprojet.web.security.MonprojetUserDetailsContextMapper" />
     
     
    <beans:bean id="ldapAuthProvider"
    	class="com.masociete.monprojet.web.security.MonprojetLdapAuthenticationProvider">
    	<beans:constructor-arg index="0">
    		<beans:bean
    			class="com.masociete.monprojet.web.security.MonprojetBindAuthenticator">
    			<beans:constructor-arg index="0" ref="contextSource" />
    			<beans:property name="userSearch" ref="ldapUserSearch" />
    		</beans:bean>
    	</beans:constructor-arg>
    	<beans:constructor-arg index="1"
    		ref="extragroupAuthoritiesPopulator" />
     
    	<beans:property name="userDetailsContextMapper" ref="monprojetUserDetailsContextMapper" />
    </beans:bean>
     
    <authentication-manager alias="authenticationManager">
    	<authentication-provider ref="ldapAuthProvider" />
    </authentication-manager>
    En fait, c'est ton code qui m'a donné l'idée de créer MonprojetLdapAuthenticationProvider et MonprojetBindAuthenticator.

    Pour l'instant, j'arrive un peu à tout, y compris à changer le code/clé du message, en me mettant directement dans le doAuthentication de MonprojetLdapAuthenticationProvider, sauf le login vide... Arf... Mais je crois que c'est de ma faute :-(

    Et ta méthode clearAuthenticateFormData me plait bien.

Discussions similaires

  1. Changer les messages d'erreur venant de mysql.
    Par ZOlivier dans le forum W4 Express
    Réponses: 6
    Dernier message: 25/09/2007, 14h32
  2. Réponses: 5
    Dernier message: 16/08/2005, 12h15
  3. [Message d'erreur] gérer les message d'erreurs
    Par heid dans le forum Langage
    Réponses: 2
    Dernier message: 12/10/2004, 14h57
  4. recuperer les messages d'erreurs de interbase
    Par devalender dans le forum Bases de données
    Réponses: 2
    Dernier message: 23/06/2004, 11h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo