This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository coselmar. See http://git.codelutin.com/coselmar.git commit b65a15c6efb0393b18cfe28f7bbcad6d73be0c7a Author: Yannick Martel <martel@©odelutin.com> Date: Mon Nov 24 15:50:27 2014 +0100 Add Login logic in UI --- coselmar-rest/src/main/resources/mapping | 2 +- .../coselmar/services/UsersWebServiceTest.java | 2 +- coselmar-ui/pom.xml | 2 +- coselmar-ui/src/main/webapp/index.html | 36 +++++-- coselmar-ui/src/main/webapp/js/angular-jwt.js | 119 +++++++++++++++++++++ .../src/main/webapp/js/coselmar-controllers.js | 36 ++++++- .../src/main/webapp/js/coselmar-user-services.js | 10 +- coselmar-ui/src/main/webapp/js/coselmar.js | 10 +- 8 files changed, 201 insertions(+), 16 deletions(-) diff --git a/coselmar-rest/src/main/resources/mapping b/coselmar-rest/src/main/resources/mapping index a84b4c0..9c9cfcf 100644 --- a/coselmar-rest/src/main/resources/mapping +++ b/coselmar-rest/src/main/resources/mapping @@ -40,5 +40,5 @@ GET /v1/users UsersWebService.getUsers GET /v1/users/{userId} UsersWebService.getUser POST /v1/users UsersWebService.addUser DELETE /v1/users/{userId} UsersWebService.deleteUser -POST /v1/login UsersWebService.login +POST /v1/users/login UsersWebService.login diff --git a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/UsersWebServiceTest.java b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/UsersWebServiceTest.java index 0cb2cc4..0a398b8 100644 --- a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/UsersWebServiceTest.java +++ b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/UsersWebServiceTest.java @@ -38,7 +38,7 @@ public class UsersWebServiceTest extends AbstractCoselmarWebServiceTest { HttpResponse addUserResponse = addUserRequest.execute().returnResponse(); Assert.assertEquals(200, addUserResponse.getStatusLine().getStatusCode()); - Request loginRequest = createRequest("/v1/login") + Request loginRequest = createRequest("/v1/users/login") .addParameter("mail", "test@test.org") .addParameter("password", "iamatester") .Post(); diff --git a/coselmar-ui/pom.xml b/coselmar-ui/pom.xml index 1e0ddcb..7a4c76c 100644 --- a/coselmar-ui/pom.xml +++ b/coselmar-ui/pom.xml @@ -48,7 +48,7 @@ <dependency> <groupId>org.nuiton.js</groupId> <artifactId>nuiton-js-angularjs</artifactId> - <version>1.3.0-beta.7-1</version> + <version>1.3.2-1</version> <scope>runtime</scope> </dependency> diff --git a/coselmar-ui/src/main/webapp/index.html b/coselmar-ui/src/main/webapp/index.html index 15ca893..1642334 100644 --- a/coselmar-ui/src/main/webapp/index.html +++ b/coselmar-ui/src/main/webapp/index.html @@ -31,12 +31,14 @@ <script src="nuiton-js/angular-route.js"></script> <script src="nuiton-js/angular-resource.js"></script> <script src="nuiton-js/angular.js"></script> + <script src="nuiton-js/angular-messages.js"></script> <script src="nuiton-js/angular-ui-bootstrap.js"></script> <script src="nuiton-js/bootstrap.js"></script> - <script src="js/coselmar-controllers.js"></script> - <script src="js/coselmar-services.js"></script> - <script src="js/coselmar-user-services.js"></script> - <script src="js/coselmar.js"></script> + <script src="js/angular-jwt.js"></script> + <script src="js/coselmar.js"></script> + <script src="js/coselmar-controllers.js"></script> + <script src="js/coselmar-services.js"></script> + <script src="js/coselmar-user-services.js"></script> </head> <body> @@ -60,10 +62,10 @@ <nav class="hidden-xs"> <ul class="nav navbar-nav"> <a href="#" role="button" class="navbar-brand">Coselmar Traceability</a> - <li class="dropdown"> + <li class="dropdown" ng-if="currentUser.userRole == 'ADMIN'"> <a href="#/users" class="dropdown-toggle">User</a> </li> - <li class="dropdown"> + <li class="dropdown" ng-if="currentUser"> <a href="#/documents" role="button" class="dropdown-toggle">Documents</a> </li> <li class="dropdown"> @@ -74,6 +76,27 @@ </ul> </li> </ul> + + <!-- Login Part --> + <form class="navbar-form navbar-right" role="form" ng-if="!currentUser"> + <div class="form-group"> + <input type="text" placeholder="Mail" class="form-control" ng-model="loginMail"> + </div> + <div class="form-group"> + <input type="password" placeholder="Password" class="form-control" ng-model="loginPassword"> + </div> + <button type="submit" class="btn btn-success" ng-click="login(loginMail, loginPassword)">Sign in</button> + </form> + <div ng-init="loginMessage = {fail: false}" class="navbar-form navbar-right"> + <ng-messages for="loginMessage"> + <ng-message when="fail"><div class="alert alert-danger alert-dismissible"><button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>Invalid Credentials</div></ng-message> + </ng-messages> + </div> + + <form class="navbar-form navbar-right" role="form" ng-if="currentUser"> + <div class="form-group">{{currentUser.userFirstName}} {{currentUser.userName}}</div> + <button type="submit" class="btn btn-danger" ng-click="logout()">Logout</button> + </form> </nav> <nav class="visible-xs" collapse="!isCollapsed"> <ul class="nav navbar-nav"> @@ -88,7 +111,6 @@ <div class="header-placeholder"></div> </div> </header> - <div ng-view class="container"></div> diff --git a/coselmar-ui/src/main/webapp/js/angular-jwt.js b/coselmar-ui/src/main/webapp/js/angular-jwt.js new file mode 100644 index 0000000..09f796f --- /dev/null +++ b/coselmar-ui/src/main/webapp/js/angular-jwt.js @@ -0,0 +1,119 @@ +(function() { + + +// Create all modules and define dependencies to make sure they exist +// and are loaded in the correct order to satisfy dependency injection +// before all nested files are concatenated by Grunt + +// Modules +angular.module('angular-jwt', + [ + 'angular-jwt.interceptor', + 'angular-jwt.jwt' + ]); + + angular.module('angular-jwt.interceptor', []) + .provider('jwtInterceptor', function() { + + this.authHeader = 'Authorization'; + this.authPrefix = 'Bearer '; + this.tokenGetter = function() { + return null; + } + + var config = this; + + this.$get = ["$q", "$injector", "$rootScope", function ($q, $injector, $rootScope) { + return { + request: function (request) { + if (request.skipAuthorization) { + return request; + } + + request.headers = request.headers || {}; + // Already has an Authorization header + if (request.headers[config.authHeader]) { + return request; + } + + var tokenPromise = $q.when($injector.invoke(config.tokenGetter, this, { + config: request + })); + + return tokenPromise.then(function(token) { + if (token) { + request.headers[config.authHeader] = config.authPrefix + token; + } + return request; + }); + }, + responseError: function (response) { + // handle the case where the user is not authenticated + if (response.status === 401) { + $rootScope.$broadcast('unauthenticated', response); + } + return $q.reject(response); + } + }; + }]; + }); + + angular.module('angular-jwt.jwt', []) + .service('jwtHelper', function() { + + this.urlBase64Decode = function(str) { + var output = str.replace('-', '+').replace('_', '/'); + switch (output.length % 4) { + case 0: { break; } + case 2: { output += '=='; break; } + case 3: { output += '='; break; } + default: { + throw 'Illegal base64url string!'; + } + } + return window.atob(output); //polifyll https://github.com/davidchambers/Base64.js + } + + + this.decodeToken = function(token) { + var parts = token.split('.'); + + if (parts.length !== 3) { + throw new Error('JWT must have 3 parts'); + } + + var decoded = this.urlBase64Decode(parts[1]); + if (!decoded) { + throw new Error('Cannot decode the token'); + } + + return JSON.parse(decoded); + } + + this.getTokenExpirationDate = function(token) { + var decoded; + decoded = this.decodeToken(token); + + if(!decoded.exp) { + return null; + } + + var d = new Date(0); // The 0 here is the key, which sets the date to the epoch + d.setUTCSeconds(decoded.exp); + + return d; + }; + + this.isTokenExpired = function(token) { + var d = this.getTokenExpirationDate(token); + + if (!d) { + return false; + } + + // Token expired? + return !(d.valueOf() > new Date().valueOf()); + }; + }); + +}()); \ No newline at end of file diff --git a/coselmar-ui/src/main/webapp/js/coselmar-controllers.js b/coselmar-ui/src/main/webapp/js/coselmar-controllers.js index dba80a1..7c61138 100644 --- a/coselmar-ui/src/main/webapp/js/coselmar-controllers.js +++ b/coselmar-ui/src/main/webapp/js/coselmar-controllers.js @@ -24,13 +24,43 @@ var coselmarControllers = angular.module('coselmarControllers', []); // Controller when the main page/view loads -coselmarControllers.controller("HomeCtrl", ['$scope', '$http', - function ($scope, $http) { +coselmarControllers.controller("HomeCtrl", ['$scope', '$http', '$location', 'userService', 'jwtHelper', + function ($scope, $http, $location, userService, jwtHelper) { + + var jwtToken = localStorage.getItem('coselmar-jwt'); + if (jwtToken && !jwtHelper.isTokenExpired(jwtToken)) { + $scope.currentUser = jwtHelper.decodeToken(jwtToken); + } //Just get the version from a file $http.get('version.txt', {'transformResponse':angular.identity}).success(function (data) { $scope.version = data; }); + + $scope.login = function(mail, password) { + userService.login(mail, password, function(successResult) { + // Store JsonWebToken to keep authentication + localStorage.setItem('coselmar-jwt', successResult.jwt); + $scope.currentUser = jwtHelper.decodeToken(successResult.jwt); + + // Manage login messages + $scope.loginMessage.fail = false; + + // Redirect on '/' + $location.path('/'); + + }, function(errorResult) { + // Error message for login + $scope.loginMessage.fail = true; + }) + } + + $scope.logout = function() { + delete $scope.currentUser; + localStorage.removeItem('coselmar-jwt'); + $location.path('/'); + } + }]); // Controller for All Documents View @@ -87,7 +117,7 @@ coselmarControllers.controller("DocumentViewCtrl", $scope.deleteDocument = function(documentId){ // Call service to create a new document - var toto = documentService.deleteDocument(documentId, $scope, function() { + documentService.deleteDocument(documentId, $scope, function() { // Go back to documents list $location.path("/documents"); }); diff --git a/coselmar-ui/src/main/webapp/js/coselmar-user-services.js b/coselmar-ui/src/main/webapp/js/coselmar-user-services.js index 04357ba..a829b19 100644 --- a/coselmar-ui/src/main/webapp/js/coselmar-user-services.js +++ b/coselmar-ui/src/main/webapp/js/coselmar-user-services.js @@ -30,8 +30,8 @@ function User(resource){ this.resource = resource; -// var baseURL = "http://localhost:8081/services/v1/users"; - var baseURL = "v1/users"; + var baseURL = "http://localhost:8081/services/v1/users"; +// var baseURL = "v1/users"; this.createUser = function(user, successFunction, failFunction){ @@ -80,4 +80,10 @@ function User(resource){ } }); } + + this.login = function(mail, password, successFunction, failFunction){ + + var userResource = resource(baseURL + "/login", {mail:'@mail', password:'@password'}, {'post' : {method: 'POST'}}); + userResource.post({'mail': mail, 'password': password}, successFunction, failFunction); + } }; \ No newline at end of file diff --git a/coselmar-ui/src/main/webapp/js/coselmar.js b/coselmar-ui/src/main/webapp/js/coselmar.js index 1a342e2..409647b 100644 --- a/coselmar-ui/src/main/webapp/js/coselmar.js +++ b/coselmar-ui/src/main/webapp/js/coselmar.js @@ -21,7 +21,7 @@ * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ -var coselmarApp = angular.module("coselmarApp", ['ngRoute', 'ngResource', 'coselmarControllers', 'coselmarServices']); +var coselmarApp = angular.module("coselmarApp", ['ngRoute', 'ngResource', 'ngMessages', 'angular-jwt', 'coselmarControllers', 'coselmarServices']); coselmarApp.config(['$routeProvider', function($routeProvider) { $routeProvider @@ -56,3 +56,11 @@ coselmarApp.config(['$routeProvider', function($routeProvider) { templateUrl : 'views/home.html' }); }]); + +// Inject Json Web Token if present in all request +coselmarApp.config(function Config($httpProvider, jwtInterceptorProvider) { + jwtInterceptorProvider.tokenGetter = function() { + return localStorage.getItem('coselmar-jwt'); + } + $httpProvider.interceptors.push('jwtInterceptor'); +}) \ No newline at end of file -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.