[AngularJs + Php Mysql] Gérer l’identification et les droits.

angularjslogo-php

Introduction


Voici ma méthode la plus récente et la plus claire, pour créer un système d’identification et d’affectations de  droits dans une application ANGULARJS avec un Back End PHP-MYSQL.

Finalement, une fois que l’on a compris, ce n’est pas si dur. Bien sur, il existe d’autres techniques, mais celle ci à le mérite de fonctionner.

Pour l’étape 3, il est possible que cela soit sujet à hacking, vu que le contrôle est effectué en JS, il faudrait donc faire la partie discrimination en fonction du rôle dans la partie Back End, cependant, cela fonctionne déjà comme cela. j’ai déjà mon idée pour passer la restriction CRUD en Back end : Le rôle de l’utilisateur sera passé en variable de session PHP, puis le test sera fait sur chaque fonction CRUD Update ou Delete ou Create, dans le back end, du coup avec le copié collé, tout fonctionnera de suite.

Principe général


  • Une table SQL des utilisateurs contient l’id, le nom, le prénom, l’Email, le mot de passe, le rôle de chaque utilisateur. (On peut bien sur ajouter la photo et pleins d’autres trucs…)
  • Une requête AJAX envoi le couple email/mot de passe de la vue identification au back end Php-Mysql qui teste si la correspondance email/mot de passe est valide.
  • C’est le Back end Php-Mysql (En technologie PDO) qui apporte la réponse, celle ci est testée dans la fonction de rappel de la requête $http de AngularJS.
  • un service AngularJs stocke l’intégralité des variables de l’utilisateur(C’est un objet JSON), si la réponse du back end PhpMysql est valide.
  • Les droits sont vérifiés lors de chaque requêtes CRUD UPDATE et INSERT, si le rôle de l’utilisateur est ADMIN ou SUPERUTILISATEUR, alors la requête est acceptée, si les droits de l’utilisateur est UTILISATEURSIMPLE, alors la requête est rejetée et l’utilisateur ne peut ni updater ni écrire. (Note : Il est aussi possible de le faire avec un interceptor mais c’est plus compliqué.)
  • Il est également possible de restreindre l’accès à des vues en fonction du rôle de l’utilisateur  dans le routeur AngularJs ngRoute.

Principes non traités dans cette doc :

  • Ensuite, si on actualise l’application lors de l’appui sur la touche F5, le service perds l’objet utilisateur, il faut alors utiliser le web Storage pour éviter à l’utilisateur de se re-logger sans cesse, et créer un objet Json ‘utilisateur’ persistant dans la mémoire du navigateur.
  • Création CRUD des utilisateurs
  • Cryptage MD5 du mot de passe

Schéma :


schf.jpg

Le code :


Dans Mysql Workbench, créer la table SQL suivante (La nommer utilisateurs) :

table.jpg

Dans le routing angularJS dans le fichier app.js, établir la relation entre la vue et le controleur (Attention, chaque controleur est un fichier .JS qui doit être chargé dans index.html).
Pour avoir plus d’infos simples sur comment marche le système de routing de vues AngularJs, c’est ici :
:


var app = angular.module('neutre', ['ngRoute','oc.lazyLoad',
'ui.bootstrap',
'ngMessages',
'llNotifier',
'ui.calendar',
'ui.knob',
'textAngular',
'scrollable-table',
'ui.select',
'vs-repeat'
])

/* ROUTING DE VUES */
app.config(function ($routeProvider, $locationProvider,$ocLazyLoadProvider){

	$routeProvider
	.when('/accueil', {
	  templateUrl: 'vues/accueil.html',
	  controller: 'accueilCtrl',

	})

	  .when('/identification', {
		templateUrl: 'vues/identification.html',
		controller: 'identificationCtrl'
     })

	 .when('/moncompte', {
		templateUrl: 'vues/moncompte.html',
		controller: 'moncompteCtrl'
     })

	.otherwise({redirectTo: '/accueil'});
})

Dans la vue AngularJs identification.html qui va servir à s’identifier, coller le code suivant afin d’afficher l’interface utilisateur de connexion:

<div class="row ">
	<div class="col-lg-12 " >
		 <div class="panel panel-warning">

			<div class="panel-heading">
				<span class="glyphicon glyphicon-log-in" aria-hidden="true"></span>  Identification : Pour la démo, utilisez l'email utilisateur@gmail.com et le mot de passe utilisateur
			</div>

			<div  class="panel-body " >
				<div class="row">
					<div class="col-md-12" >

						<div class="col-md-6 col-md-offset-3">
						<!-- <h2>S'identifier</h2> -->
							<form class="form-signin " name="myForm">
								<!-- <h2 class="form-signin-heading">Identifiez vous </h2> -->
								<label for="inputEmail" class="sr-only">Email</label>
								<input ng-model="email" type="email" class="form-control" placeholder="Email" required autofocus>
								<br>
								<label for="inputPassword" class="sr-only">Mot de Passe</label>
								<input ng-model="motdepasseATester" class="form-control" placeholder="Mot de Passe" required>
								<div class="checkbox">
								  <label>
									<input type="checkbox" value="remember-me"> Se souvenir de moi
								  </label>
								</div>
								<button ng-click="myForm.$valid && identificationUtilisateur()" class="btn btn-lg btn-primary btn-block" type="submit">S'identifier sur Mysql avec Php.</button>
					
							</form>
						</div>

					</div>
				</div>
			</div>

			<div class="panel-footer text-right">

			</div>

		 </div>
	</div>
</div> 

Ce qui nous donne dans l’application :

ide

Le controleur identificationCtrl va envoyer une requête AJAX qui permet de tester si le couple email/motdepasse renseigné est valable, lors du clic sur le bouton de l’interface :


/* CONTROLEUR DE LA VUE Identification */
app.controller('identificationCtrl', function($scope,$http, notifier,stockeUtilisateur,$location) {	

 $scope.identificationUtilisateur = function(){
        /* Test puis validation du couple login-mot de passe */
        $http.post('crud.php?action=get_login',{
                'email' : $scope.email,
                'motdepasseATester' : $scope.motdepasseATester,
            }
            ).success(function (data, status, headers, config) {
				/* Si le Login est réussi : */
				console.log(data.statuslogin);
                if( data.statuslogin != 0 ){

					notifier.notify('Login réussi');
	

					/* STOCKAGE DES DONNEES DE LUTILISATEUR DANS LE SERVICE */
                    stockeUtilisateur.setUtilisateur(data[0]); // Stocke l utilisateur dans le service angular pour  que l'application sache qui est l'utilisateur
                    $scope.Utilisateur = stockeUtilisateur.getUtilisateur();
					console.log('json '+$scope.Utilisateur.nom);

					/* ORIENTATION SUR LA VUE MONCOMPTE */
					$location.path('/moncompte');

				}
				/* Si le Login est raté : */
                else{
					notifier.notify('Login raté');
                }
            }).error(function(data, status, headers, config){
				notifier.notify('pas de connexion vers le serveur');
            });
    }

/* FIN DU CONTROLEUR */
})

Le Back End en Php MYSQL reçois les 2 variables email et mot de passe et teste si la correspondance est exacte dans la table mysql, si la correspondance est exacte, le script PHP envoie l’objet JSON contenant toutes les variables de l’utilisateur au controleur angularJS.
La fonction de rappel du controleur AngularJs va alors :
– Stocker l’utilisateur Actuel dans le service stockeUtilisateur, celui-ci sera alors disponible dans toute l’application
– Orienter l’utilisateur sur la vue moncompte grâce à $location.path :


/* -------------------------------------------------BACK END EN PDO------------------------------------------  */

include('connexionConfig.php'); 

header( 'content-type: text/html; charset=utf-8' );
error_reporting(E_ALL ^ E_NOTICE); // important pour ne pas afficher les notice PHP sans cela le script ne marche pas.

/**  Switch Case pour récupérer la l'action demandée par le controleur  Angular **/

switch($_GET['action'])  {
	case 'get_login' :	get_login();
    break;
}

 /* --------------------------------------------------DIVERS  ------------------------------------------*/
/*Function qui teste le login: */
 function get_login() {  

    /* Reception des données login a tester en base de donnée */
    $data = json_decode(file_get_contents("php://input"));
	try {
		$DB = connection();
		$sql = "SELECT * from utilisateurs WHERE utilisateurs.email = :email";
		$stmt = $DB->prepare($sql);
		$stmt->bindParam(':email',$data->email,PDO::PARAM_STR);
		$stmt->execute();
		$tab = $stmt->fetchAll(PDO::FETCH_ASSOC);

		/*  Teste si le password écrit par l'utilisateur est egal au password dans la base de données. */
		if($data->motdepasseATester==$tab[0]['motdepasse']){
            /* renvoie les variables id et email et mot de passe de l'utilisateur au script angularJs*/
            print_r(json_encode($tab));
        }
        else {
             /* Afficher false au script angularJs qui va afficher une erreur de login */
			$reponse['statuslogin']=0;
			print_r(json_encode($reponse));

        }
		$DB=null;
	} catch (PDOException $e) {
		file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);
		die();
	}	

}

Voici le service AngularJs qui va contenir un objet utilisateur, remarquer qu’il faut écrire « app » au tout début :

/* SERVICE QUI STOCKE L UTILISATEUR APRES LE LOGIN, CEST UTILE POUR UNE APPLICATION MULTI UTILISATEUR DE SAVOIR QUI EST LOGGE*/
app.service('stockeUtilisateur', function() {
   var utilisateur ={};

    return {
        getUtilisateur: function() {
            return utilisateur;
        },
        setUtilisateur: function(value) {
            utilisateur = value;
        }
    };
})

Voici la vue moncompte.html qui va afficher les détails du compte de l’utilisateur :

<div class="row ">
	<div class="col-lg-12 " >
		 <div class="panel panel-warning">
			
			<div class="panel-heading"> 
				<span class="glyphicon glyphicon-user" aria-hidden="true"></span> Mon Compte
			</div>
		
			
			<div  class="panel-body " style="min-height:700px">
				<div class="row" style="margin-top:5%">
					<div class="col-md-12" >
						
						<div class="col-md-6 col-md-offset-3 " >
						
							<form class="form-signin " name="myForm"> 
								
								<div class="input-group">
									<span class="input-group-addon" >Image</span>
									<img src = "{{utilisateur.image}}" id="nouvelleImage" class = "img-responsive" style ="width : 150px; height:150px;">
								</div><br>
								
								<div class="input-group">
									<span class="input-group-addon" >Id</span>
									<input class="form-control" ng-model="utilisateur.id" disabled> </input>
								</div><br>
								
								<div class="input-group">
									<span class="input-group-addon" >Nom</span>
									<input class="form-control" ng-model="utilisateur.nom" required> </input>
								</div><br>
								
								<div class="input-group">
									<span class="input-group-addon">Prénom</span>
									<input class="form-control" ng-model="utilisateur.prenom" required> </input>
								</div><br>
								
								<div class="input-group">
									<span class="input-group-addon">Role</span>
									<select class="form-control" ng-model="utilisateur.role" class="  form-control form-field ">
									<option value="" >Choisir le rôle</option>
										<option  value="admin">Admin</option>
										<option  value="superutilisateur">Super Utilisateur</option>
										<option  value="utilisateur">Utilisateur</option> 							
									</select>
								</div><br>
								
								<div class="input-group">
									<span class="input-group-addon" >Email</span>
									<input class="form-control" ng-model="utilisateur.email" required> </input>
								</div><br>
								
								<div class="input-group">
									<span class="input-group-addon">Mot de Passe</span>
									<input class="form-control" ng-model="utilisateur.motdepasse" required> </input>
								</div><br>
								
								
								
								<button ng-click="myForm.$valid && appliquer()" class="btn btn-lg btn-primary btn-block" type="submit">Mettre à jour.</button>
				
							</form>
						</div>
	
					</div>
				</div>
			</div>
			
			<div class="panel-footer text-right">

			</div>
			
		 </div>
	</div>
</div> 


 

Ce qui nous donne ça :

compte.jpg

 

 

Voici le controleur moncompteCtrl.js qui gère la vue moncompte.html, on voit qu’il va acquérir les données de l’utilisateur dans le service stockeutilisateur puis les affiche :

/* CONTROLEUR DE LA VUE MONCOMPTE*/
app.controller('moncompteCtrl', function($scope,$http, notifier,stockeUtilisateur) {	

	 $scope.utilisateur = stockeUtilisateur.getUtilisateur();

/* FIN DU CONTROLEUR */
})

ETAPE 2 Restreindre les droits d’une vue AngularJs à un utilisateur non identifié:


Pour faire cela, on se rends dans notre système de routing de vues AngularJS, ngroute, que l’on a vu au début de la doc, et on ajoute un resolve  :

/*
ROUTING DE VUES */
app.config(function ($routeProvider, $locationProvider,$ocLazyLoadProvider){

	$routeProvider
	.when('/accueil', {
	  templateUrl: 'vues/accueil.html',
	  controller: 'accueilCtrl',
	  resolve:{
        "check":function(stockeUtilisateur,$location){
		u = stockeUtilisateur.getUtilisateur();

            if(u.role=='admin'){
                 alert("ok");
            }else{
                $location.path('/identification');    //redirect user to home.
                alert("Vous devez vous identifier pour utiliser cette partie");
            }
        }
		}
	})

	  .when('/identification', {
		templateUrl: 'vues/identification.html',
		controller: 'identificationCtrl'
     })

	 .when('/moncompte', {
		templateUrl: 'vues/moncompte.html',
		controller: 'moncompteCtrl'
     })

	.otherwise({redirectTo: '/accueil'});
})

Explication du code :
Si le rôle de l’utilisateur stocké dans le service stockeUtilisateur n’est pas admin, il ne peux pas voir la vue accueil et est redirigé vers la vue identification !

Etape 3 : Empêcher un utilisateur d’écrire ou de mettre à jour :

Lorsque l’on a crée une requête $http Ajax, on vérifie d’abord si l’utilisateur a le droit sur la requête $http, exemple :

app.controller('citernesCtrl', function($scope,$http,notifier,stockeUtilisateur) {
/* INITIATLISATION DE BASE DES DONNEES */
$scope.citerne = {}; // Contient un seul
$scope.citernes=[]; // contient tous
u = stockeUtilisateur.getUtilisateur();
/* DELETE */
$scope.supprimer = function(idBdd){
	if(u.role=='admin'){
		$scope.citernes.splice(id,1);
	        $http.post('crud.php?action=delete_citerne',{'id':idBdd}).success(function(data){
			$scope.liste();
		}).error(function(data){ $scope.infos = " Pas de données ou pb de connexion"});
		$scope.citerne = {};
	}
	else{
		notifier.notify('Vous devez être admin pour supprimer un élément');
	}
}

/* FIN DU CONTROLEUR */

})
Publicités