Back-End

30 jul, 2014

Autenticação baseada em tokens com Silex e AngularJS

Publicidade

Seguindo a linha do meu último artigo, hoje vamos criar um aplicativo AngularJS que utiliza o Silex Backend que criamos anteriormente. A ideia é usá-lo em um aplicativo PhoneGap/Cordova executado em um dispositivo móvel.

O aplicativo mostrará um formulário de login se o dispositivo não tiver um token correto.

token-1
E com o token correto:

token-2
Nada de outro mundo, né?

Nosso aplicativo front-end vai usar AngularJS e Topcoat:

<!DOCTYPE html>
<html xmlns:ng="http://angularjs.org" lang="es" ng-app="G">
<head>
    <meta charset="utf-8"/>
    <meta name="format-detection" content="telephone=no"/>
    <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
    <meta name="viewport"
          content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi"/>
    <link rel="stylesheet" type="text/css" href="/bower_components/topcoat/css/topcoat-mobile-light.min.css">
    <title>Gonzalo Login Example</title>
</head>
<body ng-controller="MainController">
 
<div ng-view class="main-content"></div>
 
<script src="/bower_components/angular/angular.min.js"></script>
<script src="/bower_components/angular-route/angular-route.min.js"></script>
 
<script src="js/app.js"></script>
<script src="js/services.js"></script>
 
</body>
</html>

E o nosso aplicativo AngularJS:

'use strict';
var appControllers, G;
var host = 'http://localhost:8080'; // server API url
 
appControllers = angular.module('appControllers', []);
G = angular.module('G', ['ngRoute', 'appControllers']);
 
G.run(function (httpG) {
    httpG.setHost(host);
});
 
G.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.
        when('/login', {templateUrl: 'partials/login.html', controller: 'LoginController'}).
        when('/home', {templateUrl: 'partials/home.html', controller: 'HomeController'});
}]);
 
appControllers.controller('HomeController', ['$scope', 'httpG', '$location', function ($scope, httpG, $location) {
    $scope.hello = function () {
        httpG.get('/api/info').success(function (data) {
            if (data.status) {
                alert("Hello " + data.info.name + " " + data.info.surname);
            }
        });
    };
 
    $scope.logOut = function () {
        alert("Good bye!");
        httpG.removeToken();
        $scope.isAuthenticated = false;
        $location.path('login');
    };
}]);
 
appControllers.controller('MainController', ['$scope', '$location', 'httpG', function ($scope, $location, httpG) {
    $scope.isAuthenticated = false;
 
    if (httpG.getToken()) {
        $scope.isAuthenticated = true;
        $location.path('home');
    } else {
        $location.path('login');
    }
}]);
 
 
appControllers.controller('LoginController', ['$scope', '$location', 'httpG', function ($scope, $location, httpG) {
    $scope.user = {};
 
    $scope.doLogIn = function () {
        httpG.get('/auth/validateCredentials', {user: $scope.user.username, pass: $scope.user.password}).success(function (data) {
            if (data.status) {
                httpG.setToken(data.info.token);
                $scope.isAuthenticated = true;
                $location.path('home');
            } else {
                alert("login error");
            }
        }).error(function (error) {
            alert("Login Error!");
        });
    };
 
    $scope.doLogOut = function () {
        httpG.removeToken();
    };
}]);

Nesse exemplo, estou usando angular-route para lidar com as rotas do aplicativo. Hoje, estou mudando para angular-ui-router, mas nesse exemplo ainda estou usando rotas “à moda antiga”. Definimos duas parciais:

partial/home.html

<div class="topcoat-button-bar full" style="position: fixed; bottom: 0px;">
    <label class="topcoat-button-bar__item">
        <button class="topcoat-button full" ng-click="logOut()">
            <span class="">Logout</span>
        </button>
    </label>
    <label class="topcoat-button-bar__item">
        <button class="topcoat-button--cta full" ng-click="hello()">
            <span class="">Hello</span>
        </button>
    </label>
</div>

partial/login.html

<div class="topcoat-navigation-bar">
    <div class="topcoat-navigation-bar__item center full">
        <h1 class="topcoat-navigation-bar__title">Login</h1>
    </div>
</div>
 
<ul class="topcoat-list__container">
    <li class="topcoat-list__item center">
        <input ng-model="user.username" class="topcoat-text-input--large" type="text" name="user"
               placeholder="Username"/>
    </li>
    <li class="topcoat-list__item center">
        <input ng-model="user.password" class="topcoat-text-input--large" type="password" name="pass"
               placeholder="Password"/>
    </li>
</ul>
 
<div class="topcoat-button-bar full" style="position: fixed; bottom: 0px;">
    <label class="topcoat-button-bar__item">
        <button class="topcoat-button--cta full" ng-click="doLogIn()">
            <span class="">Login</span>
        </button>
    </label>
</div>

Como podemos ver, estamos usando no aplicativo um serviço para manipular conexões HTTP com as informações do token.

'use strict';
 
G.factory('httpG', ['$http', '$window', function ($http, $window) {
    var serviceToken, serviceHost, tokenKey;
    tokenKey = 'token';
    if (localStorage.getItem(tokenKey)) {
        serviceToken = $window.localStorage.getItem(tokenKey);
    }
 
    $http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
 
    return {
        setHost: function (host) {
            serviceHost = host;
        },
 
        setToken: function (token) {
            serviceToken = token;
            $window.localStorage.setItem(tokenKey, token);
        },
 
        getToken: function () {
            return serviceToken;
        },
 
        removeToken: function() {
            serviceToken = undefined;
            $window.localStorage.removeItem(tokenKey);
        },
 
        get: function (uri, params) {
            params = params || {};
            params['_token'] = serviceToken;
            return $http.get(serviceHost + uri, {params: params});
        },
 
        post: function (uri, params) {
            params = params || {};
            params['_token'] = serviceToken;
 
            return $http.post(serviceHost + uri, params);
        }
    };
}]);

 

E isso é tudo, pessoal! Vocês podem checar a minha conta no GitHub para ver um exemplo completo.

***

Artigo traduzido pela Redação iMasters com autorização do autor. Publicado originalmente em http://gonzalo123.com/2014/06/09/token-based-authentication-with-silex-and-angularjs/