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

 C++ Discussion :

Mutateur et accesseur sur énumération


Sujet :

C++

  1. #1
    Nouveau membre du Club Avatar de stallaf
    Homme Profil pro
    Inscrit en
    Novembre 2007
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 79
    Points : 39
    Points
    39
    Par défaut Mutateur et accesseur sur énumération
    Bonjour à tous et à toutes

    J'ai un type non reconnu sans savoir comment pourquoi. Voici le code et les erreurs correspondantes :
    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
     
    class UserSingleton : public Singleton<UserSingleton> {
     
    friend class Singleton<UserSingleton>;
     
    public:
        	void set_name( const QString &newName ) { this->name = newName; }
        	void set_pass( const QString &newPass ) { this->pass = newPass; }
     
            void set_rights( rights newRights ) {  //  ‘rights’ has not been declared 
        		e_rights rights;
        		rights = newRights; // invalid conversion from ‘int’ to ‘UserSingleton::e_rights’ 
    		}
     
        	inline const QString get_name() const { return this->name; }
        	inline const QString get_pass() const { return this->pass; }
        	inline const e_rights get_rights() const { return  this->rights; }
    /* ‘e_rights’ does not name a type */
     
    private:
        	UserSingleton();
        	~UserSingleton();
        	static UserSingleton * userInstance;
        	QString name;
        	QString pass;
        	typedef enum {
        	    root,
        	    settings,
        	    remove,
        	    create,
        	    modify,
        	    print,
        	    search,
        	    none
        	} e_rights;
        	e_rights rights;
    };
    Pouvez-vous me renseigner ? Merci d'avance.
    Intuitu Personae

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    L'énumération n'est pas définie au moment de son utilisation et il y a un imbroglio entre le type et les noms de variables dans set_rights :
    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
    class UserSingleton : public Singleton<UserSingleton> {
     
    friend class Singleton<UserSingleton>;
    enum e_rights{
        root,
        settings,
        remove,
        create,
        modify,
        print,
        search,
        none
    } ;
     
    public:
        	void set_name( const QString &newName ) { this->name = newName; }
        	void set_pass( const QString &newPass ) { this->pass = newPass; }
     
            void set_rights( e_rights newRights ) {  //  ‘rights’ has not been declared
        		//e_rights rights;
        		rights = newRights; // invalid conversion from ‘int’ to ‘UserSingleton::e_rights’
    		}
     
        	inline const QString get_name() const { return this->name; }
        	inline const QString get_pass() const { return this->pass; }
        	inline const e_rights get_rights() const { return  this->rights; }
     
    private:
        	UserSingleton();
        	~UserSingleton();
        	static UserSingleton * userInstance;
        	QString name;
        	QString pass;
        	e_rights rights;
    };

  3. #3
    Nouveau membre du Club Avatar de stallaf
    Homme Profil pro
    Inscrit en
    Novembre 2007
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 79
    Points : 39
    Points
    39
    Par défaut
    Ouarffff
    Il faut que je fasse une pause, je ne vois plus rien.
    Merci
    Intuitu Personae

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    De plus, pour que les valeurs énumérées soient utilisables depuis l'extérieur (par exemple pour que tu puisse déterminer les droits de quelqu'un, ou tester la valeur renvoyée par get_rights ), il faut que l'énumération soit... publique...

    Ceci dit, il ne me semble pas vraiment opportun ni de créer un singleton pour gérer l'utilisateur, ni de proposer les mutateurs sur le nom, le mot de passe ou les droits.

    D'ailleurs, à bien y réfléchir, il ne me semble pas vraiment opportun de permettre à tout le monde de récupérer le mot de passe de l'utilisateur depuis n'importe où, en exposant un accesseur sur celui-ci

    Comme ces deux dernières phrases sont un peu lacunaires, autant te donner quelques explications et quelques pistes que tu pourrais explorer pour corriger ces "problèmes"

    Le singleton est souvent considéré, à juste titre, comme un "anti pattern", dans le sens où il y a souvent moyen de s'en passer et où les cas dans lesquels il est absolument indispensable représentent une grosse minorité des cas où l'on serait tenté d'y recourir.

    Le plus souvent, le meilleur moyen de s'assurer qu'il n'y a qu'une seule instance d'un objet qui est créé est encore... d'empêcher d'en créer plusieurs

    Si tu veux l'assurance qu'il n'y aura jamais qu'un seul utilisateur connecté à un moment donné, le mieux est encore de faire en sorte qu'il soit impossible à un utilisateur de se connecter tant que celui qui est connecté à un instant T ne s'est pas déconnecté

    De plus, les cas où tu devra effectivement disposer d'informations concernant l'utilisateur sont, malgré tout, *relativement* restreints et clairement identifiés.

    Il est dont tout à fait inutile de vouloir permettre un accès à l'utilisateur depuis n'importe où, et il "suffit" de transmettre celui-ci "quand cela se justifie"

    En ce qui concerne l'opportunité de proposer un mutateur sur le login, sur le mot de passe et sur les droits accordés:

    Un utilisateur a, typiquement, valeur d'entité: si tu change le login, le mot de passe ou les droits accordés, tu as... littéralement un autre utilisateur

    De ce fait, le mieux est peut être carrément de... définir ces informations directement à la création de l'utilisateur, idéalement, en ne permettant qu'à une seule classe de créer un utilisateur, et de ne pas donner l'occasion de les modifier une fois qu'ils ont été détfinis

    En ce qui concerne pour finir l'opportunité de fournir un accesseur sur le mot de passe:

    Typiquement, le mot de passe n'est vérifié... que lors de la connexion d'un utilisateur, à l'aide d'un "système externe" (une table de base de données, un fichier texte ou dans un format quelconque, ...) dans lequel il ne devrait même pas apparaitre en clair.

    Le système externe devrait, idéalement, assurer la persistance de cette info sous la forme d'une somme MD5 par exemple ou de tout autre somme de contrôle "sécurisante" (de la série des SHA et autres).

    Mais, quel que soit le système de cryptage envisagé, et surtout si le mot de passe est disponible en clair, il est largement préférable d'éviter à tout à chacun d'y accéder, ne serait-ce que parce qu'il deviendrait alors beaucoup trop facile d'arriver à créer une "collision" (en gros: de trouver un mot de passe ayant la même somme de contrôle).

    Si donc, tu tiens absolument à ce que l'utilisateur "trimbale" avec lui le mot de passe (et tu auras compris que je considère déjà cela comme une très mauvaise idée ), tu dois veiller à ce qu'il y ait un minimum d'endroits d'où il soit possible d'y accéder.

    Cela implique que, si tu as *réellement besoin* de permettre une comparaison entre le mot de passe d'un utilisateur et un mot de passe récupéré "par ailleurs", cela devrait se faire en passant par une fonction membre nommée, pour l'exemple, samePassWord et prenant le mot de passe à comparer en paramètre.

    Au final, ta classe utilisateur pourrait ressembler à quelque chose comme:
    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
    class User
    {
        /* on considère qu'il faut passer par UserManager pour
         * se connecter et se déconnecter ;)
         *
         * Ce sera la seule classe susceptible de créer un utilisateur :D
         */
        friend class UserManager;
        public:
            /* il est sans doute utile de permettre aux gens de tester les droits
             * d'un utilisateur :D... C'est pour cela que l'énumération est publique
             */
            enum e_rights { // au fait, le typedef est inutile en C++ :D
        	    root,
        	    settings,
        	    remove,
        	    create,
        	    modify,
        	    print,
        	    search,
        	    none
        	};
            QString const & login() const{return login_;}
            /* on permet à tout le monde de récupérer les droits de l'utilisateur
             * (note que cela devrait être murement réfléchi :D)
             */
            e_rights rights() const{return rigths_;}
            /* on permet de tester si un mot de passe correspond à celui de 
             * l'utilisateur
             */
            bool samePassWord(QString const & s) const
            {
                QString converted=MD5(s);// si mot de passe crypté, à adapter :D
                return converted==pass_;
            }
        private:
            /* constructeur et destructeur ne seront utilisés que par
             * UserManager
             */
            User(QString const & u, QString const & p, e_rights r ):
                login_(u),pass_(p),rights_(r){}
            ~User(){}
            /* C++1x permet de faire autrement, en attendant, on interdit
             * la copie et l'affectation en déclarant le constructeur par
             * copie et l'opérateur d'affectation SANS LES DEFINIR
             * dans l'accessibilité privée
             */
            User(User const &);
            User & operator=(User const &);
            /* les membres qui vont bien */
            QString login_;
            QString pass_;
            e_rights rights_;
    };
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Nouveau membre du Club Avatar de stallaf
    Homme Profil pro
    Inscrit en
    Novembre 2007
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 79
    Points : 39
    Points
    39
    Par défaut
    Merci koala01 pour toutes ces informations

    En fait, pour le moment j'expérimente et tâtonne pas mal. Voilà pourquoi l'approche est mauvaise. Je me serais bien appuyé sur quelque chose d'existant quelque part mais j'aime la découverte

    Revenons sur le fonds et apportons quelques explications Après étude des besoins, cas d'utilisation... il me faut gérer authentification et droits. Quatre groupes d'utilisateurs sont crées et je choisis de faire correspondre les droits à une liste d'actions autorisés pour chaque groupe (qui peut le plus peut le moins).

    J'utilise une base de donnée mysql et une table ou mes passes sont enregistrés en SHA1. J'ouvre l'application, vérifie la connexion puis demande login et mot de passe pour attribution des droits.

    Je pensais donc vérifier les droits avant chaque action en nécessitant et il me faut l'utilisateur accessible partout. Maintenant, le changement d'utilisateur doit être possible sans fermer l'application (fermeture de session - nouvelle connexion).

    L'objet unique me paraît bien, en effet, avec destruction de l'ancien et création d'un nouveau. Aucune modification autorisée sur cet objet, seul un accesseur pour les droits semblent bien.

    Voilà pourquoi je partais sur un singleton pensant que cela correspondait pas mal à la problématique.
    Comment ferait un programmeur expérimenté ? Quel est la moins mauvaise des solutions ? Merci pour vos conseils avisés.
    Intuitu Personae

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Ben, je commencerais par clairement déléguer les responsabilités...

    L'utilisateur n'a qu'une responsabilité: indiquer à l'application quels sont ses droits (et éventuellement permettre à l'application de savoir qui est connecté )

    La classe User serait donc proche de
    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
    class User
    {
        friend class UserManager;
        public:
            /* j'ai inversé l'ordre des droits, car les valeurs sont incrémentales
             * dans une énumération... tu peux donc "simplement" tester si
             * le droit d'utilisateur est... plus grand ou égal à celui qui est 
             * nécessaire :D
             */
            enum e_rights { 
        	    none,        
        	    search,
        	    print,
        	    modify,
        	    create,
        	    remove,
        	    settings,
        	    root
        	};
            QString const & login() const{return login_;}
            e_rights rights() const{return rigths_;}
        private:
            /* constructeur et destructeur ne seront utilisés que par
             * UserManager
             */
            User(QString const & u,e_rights r ):
                login_(u),rights_(r){}
            ~User(){}
            /* cf le message précédent ;) */
            User(User const &);
            User & operator=(User const &);
            /* les membres qui vont bien */
            QString login_;
            e_rights rights_;
    };
    J'aurais un gestionnaire de connexion à MySQL qui se contente de... gérer la connexion (créer / recréer / détruire la connexion au serveur MySQL) et de la transmettre connexion "à qui de droit" (le gestionnaire d'utilisateur et le gestionnaire de requêtes, par exemple):
    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
    class ConnectionManager
    {
            /* Comme tu travailles avec Qt, on n'autorise la création d'une 
             * instance que depuis la fenêtre principale...
             * Par facilité je choisi qu'elle s'appelle MyGUI (faudra adapter :D) 
             */
        friend class MyGUI;
        public:
            bool connected() const
            {
                // vérifie si la connexion existe et est active 
                // on "dit que" la connexion dispose d'une fonction active :D
                return (conn_!=NULL && conn->active());
            }
            // demande de se connecter au serveur
            // renvoie la connexion active 
            Connection * Connect()
            {
                // si on est déjà connecté, on renvoie la connexion
                if(connected())
                    return conn_;
                // si la connexion existe mais n'est pas active, on la recrée
                if(conn_)
                {
                    delete conn_;
                    conn_ = new Connection(server_);
               }
               return conn_;
            }
            // se déconnecte du serveur MySQL
            void disconnect()
            {
                delete conn_;
                conn_=NULL;
            }
            /* si c'est intéressant, on permet de récupérer le nom du serveur
             * et de le modifier
             */
            QString const & serverName() const{return server_;}
            void changeServer(QString const & newserver)
            {
                /* pour pouvoir le faire, on procède à la déconnexion automatique
                 */
                disconnect();
                server_=newserver;
            }
        private:
            ConnectionManager(QString const & ser):server_(ser){}
            ~ConnectionManager(){disconnect();}
            // copie et affectation interdites 
            ConnectionManager(ConnectionManager const &);
            ConnectionManager& operator=(ConnectionManager const &);
            QString server;
            Connection * conn_;
    };
    J'aurais sans doute un gestionnaire de requêtes, qui place les nouvelles requêtes dans une file, qui les envoie au serveur (via le gestionnaire de connexions) et qui place le résultat dans une autre file.

    Ce gestionnaire de requête serait "alimenté" en requêtes par... une fabrique à requêtes, et on laisserait à un "manipulateur de résultat" le soin de... traiter les résultats obtenus

    Mais bon, on peut envisager (pour la simplicité de l'explication seulement) de s'en passer pour le gestionnaire d'utilisateurs...

    Enfin, j'aurais mon gestionnaire d'utilisateurs, qui fait appel au gestionnaire de connexion (et éventuellement aux systèmes de gestion et de traitement des requêtes) pour créer l'utilisateur courent.

    Sa seule responsabilité (c'est pour cela que, normalement, il faudrait recourir à un ensemble de classes pour gérer et traiter les requêtes au serveur) est... de s'assurer que l'utilisateur peut se connecter, et que le mot de passe introduit correspond à ce qui se trouve dans la base MySQL.

    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
    class UserManager
    {
            /* Comme tu travailles avec Qt, on n'autorise la création d'une 
             * instance que depuis la fenêtre principale...
             * Par facilité je choisi qu'elle s'appelle MyGUI (faudra adapter :D) 
             */
        friend class MyGUI;
        public:
            bool createUser(QString const & u, QString const & pass)
            {
                /* si un utilisateur est déjà connecté, on refuse d'en créer un autre
                 */
                if(user_!=NULL)
                    throw UserAllreadyCreated();
                /* à toi de créer la requête, de l'envoyer au serveur MySQL...
                 * et de la traiter... je considère que tu obtiens au final une
                 * structure donnant le nombre d'enregistrement trouvé,
                 * la somme SHA-1 du mot de passe et
                 * les droits accordés à l'utilisateur appelée result
                 */
               if(result.count==0)
                   throw UserDoesntExists();
               if( SHA_1(pass)!=result.pass)
                   throw BadLoginOrPassword();
               user_=new User(u, result.rights);
               return true;
            }
            /* on permet de détruire l'utilisateur en cours de fonctionnement
             * (généralement pour permettre à un autre de se connecter :D )
             */
            void disconnectUser()
            {
                delete user_;
                 user_ = NULL;
            }
            /* on peut récupérer une référence constante sur l'utilisateur */
            User const& user()const {return *user_;}
        private:
            UserManager(ConnectionManager * cm ):user_(NULL)
                                 connManager_(cm){}
            ~UserManager(){delete user_;}
            // copie et affectation interdite
            UserManager(UserManager const &);
            UserManager& operator = (UserManager const &);
            User * user_;
            ConnectionManager * connManager_;
    };
    NOTA: UserDoesntExists, UserDoesntExists et BadLoginOrPassword sont des classes d'exception qu'il t'appartient de créer, qui te permettront d'afficher un message adapté si l'utilisateur n'est pas créé

    Pour le reste, tout se fait au niveau de la fonction principale, mais, comme tu travailles avec Qt, je présumes (peut être à tord) que tu crées une interface graphique...

    Il y a, normalement, possibilité de récupérer l'instance de QApplication depuis n'importe où... C'est donc à ce niveau là que devront se trouver les instances de ConnectionManager et de UserManager.

    Je ne met que ce qui nous intéresse, mais elle ressemblera à quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    MyGUI : public QMainWindow
    {
        public:
            MyGUI():connections_("http://127.0.0.1:port"), 
                 users_(&connManager_)
        {}
        UserManager const & users() const {return users_;}
        ConnectionManager const & connections() const{return connections_;}
        UserManager & users() {return users_;}
        ConnectionManager & connections() {return connections_;}
    }
    Comme tu n'aura qu'une instance de ton interface graphique, et qu'il n'y a, jamais qu'un gestionnaire de connexion et un gestionnaire d'utilisateur, avec, à chaque fois, une seule instance de connexion ou d'utilisateur, tu peux être sûr qu'il n'y aura... qu'un instance de connexion et une d'utilisateur (maximum) par application

    [EDIT]Est-il besoin de préciser que le code a été écrit à la volée, sans réflexion approfondie, et n'a absolument pas été testé
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Nouveau membre du Club Avatar de stallaf
    Homme Profil pro
    Inscrit en
    Novembre 2007
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 79
    Points : 39
    Points
    39
    Par défaut
    Vi, je visualisais un truc comme çà sans arriver encore à l'organiser comme tu l'as fait

    Pour sa somme SHA1 je voyais login+passe mais passe+droits c'est sans doute encore mieux.

    Superbe piste sur laquelle je vais partir travailler.

    Intuitu Personae

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    En fait, ici, il n'y a que le mot de passe qui soit crypé SHA-1...

    Ce qu'il y a, c'est que la requête SQL devrait renvoyer un ou zero (si le login n'a pas été trouvé) enregistrement avec le contenus des champs login, pass et rights de la table des utilisateurs.

    Comme il y a des chances pour que tu récupère une collection d'enregistrements (même si elle n'est composée que... d'un seul enregistrement), tu effectuerais un certain nombre de vérifications avant de créer l'utilisateur au niveau de ton application:

    1 - Avant même d'envoyer la requête au serveur, tu vérifie si... il n'y a pas déjà un utilisateur connecté.

    Si c'est le cas, c'est un premier motif pour refuser la création d'un utilisateur

    1 - Est-ce que la requête a donné au minimum un résultat

    Si tu n'a pas au moins un enregistrement, c'est que le login n'existe pas, ce qui est un deuxième motif pour refuser de créer un utilisateur

    Si tu as plusieurs enregistrements, c'est clairement que tu as "foiré" quelque chose en définissant tes clés primaires, mais il n'est pas du ressort de l'application de s'en inquiéter (tu pourrais cependant envisager d'émettre un message du genre de "la BDD semble corrompue, veuillez contacter de gestionnaire" )

    3 - La valeur du champs "password" dans la table (pour l'enregistrement renvoyé) correspond elle bien à la somme SHA-1 du mot de passe introduit par l'utilisateur

    Il s'agit bel et bien de ne crypter que... le mot de passe avec SHA-1

    Si ce n'est pas le cas, c'est que le mot de passe ne correspond pas, ce qui est un troisième motif pour refuser la création d'un utilisateur.

    Le fait de lancer une exception te permet, lorsque tu vas l'attraper, et donc d'émettre un message cohérent avec la raison pour laquelle l'utilisateur n'a pas pu se connecter

    Si tu ne rencontre aucun de ces motifs pour refuser la création d'un utilisateur, tu peux envisager de le créer correctement.

    Et, pour ton application, un utilisateur ne sera identifié que... par son login et les droits dont ils dispose

    Tu pourra donc demander le login et les droits, mais tu ne pourra modifier ni l'un ni l'autre, sous aucun prétexte

    Lorsque l'utilisateur qui dispose des "droits suffisants" pour décider de modifier ceux d'un utilisateur "lambda", il n'y aura cependant aucun problème: c'est cet utilisateur "tout puissant" qui est connecté, et qui a le droit d'accéder... au formulaire permettant de gérer les droits des autres

    Tu pourrais d'ailleurs (et ce serait sans doute à conseiller) placer des "barrières" un peu partout pour avoir la certitude que seul celui qui peut changer les droits des autres tentera de le faire, par exemple :
    1. Au moment de décider (ou non) d'afficher le formulaire de changement
    2. Au moment de décider (ou non) de créer la requête de changement
    3. Au moment de décider (ou non) d'envoyer la requête au serveur
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Nouveau membre du Club Avatar de stallaf
    Homme Profil pro
    Inscrit en
    Novembre 2007
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 79
    Points : 39
    Points
    39
    Par défaut
    Vi j'ai bien compris le mécanisme. Moi je fais SHA1(login+passe) par habitude mais bon...
    Par contre j'ai un soucis avec la fonction UserManager::createdUser.
    Pour m_user = new User(), les paramètres ne sont pas bons :
    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
    class UserManager {
       friend class pgstock;
       public:
          struct s_id {
             int count;
             QString login, pass, rights;
          };
          s_id m_result;
     
          bool create_user( QString const & u, QString const & pass ) throw( Error ) {
             if( m_user != NULL )
                throw ExecptUserAlreadyCreated(blabla);
                /* Je me connecte ici à ma tabme */
                int q = queryCount.record().count();
                s_ident.count = q;
                   if( s_ident.count == 0 )
                      throw ExceptNoUserBddRegistred(blabla)
     
                   while( queryLogin.next() ) {
                   /* je récupère ici les infos de ma table */
                      if( (name  == u) & (passe == pass) ) {
                         m_result.login = name;
    		     m_result.pass = passe;
    		     m_result.rights = rights;
    		     break;
                      }
                      else
                         throw ExceptBadLoginOrPass(blabla)
                      }
     
                      user_=new User(u, result.rights);
    /* Le constructeur de User prend son enum en argument et non la structure
    * et je n'arrive pas régler le truc
    */			
                      return true;
    }
    J'ai tenté de modifier le constructeur de la classe User, de déporter la structure m_result et autres mais sans succès.
    Intuitu Personae

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Mais tu n'a absolument pas besoin de passer par une structure interne...

    A partir du moment où tu arrive à récupérer une liste d'enregistrements depuis ta base de données, cette liste est composée:
    • du nombre d'enregistrements (que tu peux, semble-t-il, récupérer par sa fonction membrecount)
    • de l'ensemble des enregistrements trouvés grâce à la requête
    Chaque enregistrement est, quant à lui, composé par l'ensemble des champs de la table, dont:
    • le nom d'utilisateur (sans doute, sauf si tu a précisé les champs que tu voulais)
    • le mot de passe de l'utilisateur, crypté SHA-1
    • les droits de l'utilisateur
    Comme la requête est sensée ne renvoyer qu'un seul enregistrement, tu peux te dire que celui qui t'intresse est... le premier de la liste (celui qui a l'index 0 )

    De plus, il ne sert à rien de préciser le spécificateur d'exception, parce que cela sous entend que toutes les exceptions ont une base commune (cela peut être le cas), mais, surtout, parce que certaines étapes risquent elles aussi de lancer une exception (entre autre new qui pourrait lancer une std::bad_alloc).

    Si tu oublie seulement une seule des exceptions susceptibles d'être lancées, tu perdra le contexte dans lequel elle l'a été, et toute possibilité d'y remédier ou de simplement rattraper l'exception sans quitter l'application.

    En outre, je ne suis pas forcément partisan de l'utilisation de break, ne serait-ce que parce qu'il n'est pas vraiment nécessaire de respecter SESE, qui n'est, finalement, plus vraiment d'actualité en programmation structurée

    Enfin, en y réfléchissant bien, comme tout ce qui peut faire échouer la création d'un utilisateur lance une exception, il n'est finalement pas nécessaire que la fonction renvoie quelque chose

    Au final, le code pourrait tout simplement être proche de
    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
    class UserManager {
       friend class pgstock;
       public:
          bool create_user( QString const & u, QString const & pass ){
             if( m_user != NULL )
                throw ExecptUserAlreadyCreated(blabla);
               if(query.records.size()==0) // je pars du principe que query est
                                           // composée entre autre d'un std::vector
                                           // contenant les enregistrements trouvés
                      throw ExceptNoUserBddRegistred(blabla);
               /* on peut tester le cas où plusieurs enregistrements 
                * ont été renvoyés
                */
              if(query.records.size()<1)
                  trhow TooManyRecords(); // "please contact DBA"
              if(SHA_1(pass)!=query.records[0].pass)
                  throw BadLoginOrPassword();
              // si on arrive ici, on est bon pour créer l'utilisateur
              m_user = new User(u,query.records[0].rights); //peut lancer std::bad_alloc
              /* si on quitte la fonction sans avoir lancé d'exception, c'est
               * que tout s'est bien passé
               */
        }
        private:
            User * m_user;
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Nouveau membre du Club Avatar de stallaf
    Homme Profil pro
    Inscrit en
    Novembre 2007
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 79
    Points : 39
    Points
    39
    Par défaut
    J'avance en fonction de tes explications (et de l'immense disponibilité et patience dont tu fais preuve) .
    J'utilise majoritairement Qt et non la lib standard et je n'ai pas de std::vector. Mais peu importe les chemins empruntés le résultat est le même .
    J'ai cependant toujours un problème avec la ligne suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_user = new User( u, queryId.value(field1).toString() )
    J'ai le messages suivant :
    error : no matching function for call to ‘User::User(const QString&, QString)
    info : User::User(const QString&, User::e_rights)

    Tant je passerais une string en second paramètre pour les droits ce sera pareil. Cooment transformer le résultat de la requête en une énumération e_rights ?
    Intuitu Personae

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Le champs est au format numérique, non Si c'est bien le cas, pourquoi vouloir utiliser la fonction toString qui, comme son nom l'indique, transforme la valeur en chaine de caractères
    le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_user = new User( u, queryId.value(field1) );
    devrait suffir (au fait, il manquait un point virgule en fin de ligne )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #13
    Nouveau membre du Club Avatar de stallaf
    Homme Profil pro
    Inscrit en
    Novembre 2007
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 79
    Points : 39
    Points
    39
    Par défaut
    J'ai corrigé mes erreurs de logique et d'inattention. Cependant j'ai une erreur que je n'arrive pas à résoudre dans le constructeur de myGUI :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    MyGUI : public QMainWindow
    {
        public:
            MyGUI():connections_("http://127.0.0.1:port"), 
                 users_(&connManager_)
        {}
    ...
    }
    ‘connManager_’ was not declared in this scope.
    Intuitu Personae

  14. #14
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par stallaf Voir le message
    J'ai corrigé mes erreurs de logique et d'inattention. Cependant j'ai une erreur que je n'arrive pas à résoudre dans le constructeur de myGUI :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    MyGUI : public QMainWindow
    {
        public:
            MyGUI():connections_("http://127.0.0.1:port"), 
                 users_(&connManager_)
        {}
    ...
    }
    ‘connManager_’ was not declared in this scope.
    Et pour cause, il semblerait que le gestionnaire de connexion que tu as déclaré dans ta classe s'appelle... connections_

    Mais je me rend compte que j'avais effectivement fait l'erreur dans mon code (re )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [c#] Accesseurs sur tableaux d'une classe
    Par tribaleur dans le forum Windows Forms
    Réponses: 8
    Dernier message: 31/12/2009, 00h36
  2. Réponses: 5
    Dernier message: 07/02/2006, 14h05
  3. Outils pour creer les accesseurs et les mutateurs
    Par MarieMtl dans le forum MFC
    Réponses: 3
    Dernier message: 03/10/2005, 17h03
  4. [C#] [VS.NET] Peut on faire un accesseur sur objets?
    Par Designotik dans le forum Windows Forms
    Réponses: 3
    Dernier message: 06/01/2005, 21h56
  5. [Java 5] Réflexion sur les énumérations type-safe
    Par rozwel dans le forum Langage
    Réponses: 5
    Dernier message: 04/12/2004, 20h34

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