I have created a basic authentication system in an angular app which is written against hardcoded credentials - see below:
app.js
/* global app:true */
/* exported app */
'use strict';
/**
* #ngdoc overview
* #name WebAppApp
* #description
* # WebAppApp
*
* Main module of the application.
*/
var app = angular
.module('WebAppApp', [
'ngAnimate',
'ngAria',
'ngCookies',
'ngMessages',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch'
])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/login.html',
controller: 'loginCtrl',
controllerAs: 'login'
})
.when('/home', {
templateUrl: 'views/home.html'
//controller: 'loginCtrl',
//controllerAs: 'login'
})
.otherwise({
redirectTo: '/'
});
});
login.html
<form ng-submit="submit()">
Username: <input type="text" id="username" ng-model="username" /><br>
Password: <input type="password" id="password" ng-model="password" /><br>
<input type="submit" value="Submit" />
</form>
login.js
'use strict';
//app global variable
//this is hte controller that handles post requests
app.controller('loginCtrl', function ($scope, $location) {
$scope.submit = function(){
var uname = $scope.username;
var password = $scope.password;
if($scope.username == 'admin' && $scope.password == 'admin'){
$location.path('/home');
} else {
alert('username or password is wrong');
}
};
});
This works. What I want to do now, is check the username and password against an api call by posting the data to the server /login, if successful an access token is returned, and is then stored inside of a cookie. At which point the user gets access to the rest of the application.
If the credentials fails, for validation takes place preventing the user from logging in.
What is the best way to do this?
First of all check this url
Your code would look something like this:
$scope.submit = function(){
$http.post('/login', {
username:$scope.username,
password:$scope.password
}).then(function(response) {
if (response.data=="ok") {
//Login was ok
$location.path("/home");
} else {
//Login was not ok
}
}, function(response) {
//Error happend, response.status or response.statusText have details
});
}
Related
If type the username or password once wrong and change manually the URL to my home GUI, I get access to it without any authentication.
I can't explain why :/
this is my app.js, where all the routing happens and a fiddle with my controller and my html data :
(function() {
'use strict';
// declare modules
angular.module('Authentication', []);
angular.module('Home', ['naif.base64', 'ngFileSaver']);
//dependecies of the module
angular.module('JMeterGui', ['Authentication','Home','ngRoute', 'ngCookies'])
//configure the module
.config(config)
//configure the start of the module
.run(run);
//dependencies of the config module
config.$inject = ['$routeProvider', '$locationProvider', '$qProvider'];
//configure routing depends on the actual URL
function config($routeProvider, $locationProvider, $qProvider) {
$routeProvider
.when('/', {
controller: 'HomeController',
templateUrl: 'modules/home/views/home.html'
})
.when('/login', {
controller: 'LoginController',
templateUrl: 'modules/authentication/views/login.html'
})
.otherwise({ redirectTo: '/login' });
}
//dependecies of the run module
run.$inject = ['$rootScope', '$location', '$cookies', '$http'];
function run($rootScope, $location, $cookies, $http) {
// keep user logged in after page refresh
$rootScope.globals = $cookies.getObject('globals') || {};
if ($rootScope.globals.currentUser) {
$http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata;
}
$rootScope.$on('$locationChangeStart', function (event, next, current) {
// redirect to login page if not logged in
var restrictedPage = $.inArray($location.path(), ['/login']) === -1;
var loggedIn = $rootScope.globals.currentUser;
if (restrictedPage && !loggedIn) {
$location.path('/login');
}
});
}
})()
my fiddle with controller and html
Anyone knows why ?
Try to add:
if (restrictedPage && !loggedIn) {
//Prevent default
event.preventDefault();
$location.path('/login');
}
On login action I'm storing inside localstorage username and token for logged user where afterwards I'm creating auth. headers that post request.
Update:
to be more specific on this. I have userService which succ. put and retrieve users data from the localstorage, where I have username, sessionId, and isLogged.
My question is: Now having Auth. header, all info I need about logged user inside localstorage, how can I write an event handler to check if the user is logged in before each route change.
Should I do that on app.js where I init my app and to inject userService? if yes how.
(function () {
"use strict";
var app = angular.module("myApp",
["common.services",
"ui.router",
"ui.mask",
"userService",
"ui.bootstrap"]);
....
How can I now use this stored auth header in order to access/deny
access to specific pages?
Update 2: app.js
(function () {
"use strict";
var app = angular.module("myApp",
["common.services",
"ui.router",
"ui.mask",
"userService",
"ui.bootstrap"]);
app.config(["$stateProvider", "$urlRouterProvider",
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state("index", {
url: "/",
templateUrl: "app/index.html",
})
// Restricted
.state("home", {
url: "/home",
templateUrl: "app/home/home.html",
controller: "HomeController as vm"
})
}]
);
}());
i think that the right approach to your problem is to use resolve property in the route, so the user can't navigate to certain pages if he isn't logged in and once he logged in you can inject the user object to the controller
for example to navigate to home page you must be logged in
.when("/home", {
templateUrl: "homeView.html",
controller: "homeController",
resolve: {
user: function(AuthenticationService){
return AuthenticationService.getUser();
}
}
})
app.controller("homeController", function ($scope, user) {
$scope.user = user;
});
good example: https://www.sitepoint.com/implementing-authentication-angular-applications/
You can achieve this by marking required routes with custom attribute and verifying that token is valid when "location" is changing.
Update Assuming you can verify that user is authenticated by checking isLogged property of userService:
(function () {
"use strict";
var app = angular.module("myApp",
["common.services",
"ui.router",
"ui.mask",
"userService",
"ui.bootstrap"]);
app.config(["$stateProvider", "$urlRouterProvider",
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state("index", {
url: "/",
templateUrl: "app/index.html",
})
// Restricted
.state("home", {
url: "/home",
templateUrl: "app/home/home.html",
controller: "HomeController as vm",
data: {
requiresLogin: true
}
})
}]
).run(['$rootScope', '$state', 'userService', function($rootScope, $state, userService) {
$rootScope.$on('$stateChangeStart', function(e, to) {
if (to.data && to.data.requiresLogin && !userService.isLogged) {
e.preventDefault();
$state.go('index');
}
})
}]);
}());
I have this strange behaviour on my AngularFire Auth function.
The user logs in with email+password and on success it should redirect to /dash, but is redirecting to /home.
/dash is locked for unauth and work as expected, but when I log in and are being redirected to /home, if I type /dash in the browser it's accessible. So, it IS working but my redirecting behaviour is obviously wonky. Also it seems like it's trying to access /dash because it flickers by quickly before sending me to /home on successful login.
I'm using latest Angular + AngularFire + Firebase.
I've tried to set up a plunkr-view of it but it seems to be something with plunkr and firebase that doesn't work.
Anyhow, here's my auth code and my route code, all ideas are welcome!
app.controller('loginController', ['currentAuth', '$scope', '$firebaseAuth', 'Auth', '$location', '$rootScope',
function(currentAuth, $scope, $firebaseAuth, Auth, $location, $rootScope){
var ref = new Firebase('https://url.firebaseio.com');
$scope.auth = $firebaseAuth(ref);
// Login user, if true redirect to dash.html, if false, don't redirect, show error message
$scope.loginUser = function(){
$scope.auth = Auth;
$scope.auth.$authWithPassword({
email:$scope.email,
password:$scope.password
}, {
remember: 'sessionOnly'
}).then(function(authData) {
console.log('Logged in as: ', authData.uid);
$scope.auth.$onAuth(function(authData) {
$rootScope.auth = true;
$scope.auth = Auth;
$location.path('/dash.html');
})
// If error with login, catch it and prompt it
}).catch(function(error) {
$('#signBlock').text(error);
});
};
}
]);
And routes:
app.run(['$rootScope', '$location', 'Auth',
function($rootScope, $location, Auth){
$rootScope.$on('$routeChangeError',
function(event, next, previous, error){
if(error === 'AUTH_REQUIRED'){
console.log('AUTH REQ!')
$location.path('/home');
}
});
}]);
// Config for routing
app.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider){
$routeProvider
// Route for landing page
.when('/home', {
templateUrl: '/home.html',
controller: 'homeController'
})
// Route for login page
.when('/login', {
templateUrl: '/login.html',
controller: 'loginController',
resolve: {
'currentAuth': ['Auth', function(Auth){
return Auth.$waitForAuth();
}]
}
})
// Route for user dashboard
.when('/dash', {
templateUrl: '/dash.html',
controller: 'dashController',
resolve: {
'currentAuth': ['Auth', function(Auth){
return Auth.$requireAuth();
}]
}
})
.otherwise({ redirectTo: '/home' });
}]);
This issue has been posted a few times but I cannot seem to find the error within my code. Can somebody help spot the issue in my code?
Below is my app.js file
'use strict';
/**
*jslint node:true
* #ngdoc overview
* #name impApp
* #description
* # impApp
*
* Main module of the application.
*/
/*global Firebase, angular*/
angular
.module('impApp', [
'ngMessages',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch',
'firebase'
])
.config(function ($routeProvider) {
$routeProvider
.when('/main', {
templateUrl: 'views/main.html',
controller: 'MainCtrl',
controllerAs: 'main'
})
.when('/', {
templateUrl: 'views/login.html',
controller: 'AuthCtrl',
controllerAs: 'auth'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'AboutCtrl',
controllerAs: 'about'
})
.otherwise({
redirectTo: '/'
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
Secondly, this is my controller contents on "auth.js":
'use strict';
/*global Firebase, angular, console*/
angular.module('impApp')
// Re-usable factory that generates the $firebaseAuth instance
.factory("Auth", function ($firebaseAuth) {
var ref = new Firebase("https://impl.firebaseio.com");
return $firebaseAuth(ref);
})
.controller('AuthCtrl', function ($scope, $http, Auth) {
// Listens for changes in authentication state
Auth.$onAuth(function (authData) {
$scope.authData = authData;
});
// Logs in a user with email & password
$scope.login = function () {
Auth.authWithPassword({
email : $scope.email,
password : $scope.password
}, function (error, authData) {
if (error) {
console.log("Login Failed!", error);
} else {
console.log("Authenticated successfully with payload:", authData);
}
});
};
// Logs out the logged-in user
$scope.logout = function () {
Auth.$unauth();
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
Finally, I have outlined the "login.html" contents:
<div>
<form class="form-signin">
<h2 class="form-signin-heading">Please Sign In</h2>
<input type="text" class="form-control" name="username" ng-model = "username" placeholder="Email Address" required="" autofocus="" />
<input type="password" class="form-control" name="password" ng-model = "password" placeholder="Password" required=""/>
<p></p>
<button class="btn btn-lg btn-primary btn-block" type="submit" ng-click="login()">Login</button>
</form>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
Thank you Pierre-Alexandre. Adding the link to the js file in the index.html resolved this issue.
My app has a login form consisting of a username, password, and a button to click to log in. However, for some reason I just can't get ui-keypress to work on the login button. I'm using ui-bootstrap and ui-utils. ui-utils has the keypress directive included.
Here's what I have so far:
My login partial:
<div id="loginForm">
<img id="logo" src="img/login_logo.png"/>
<alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)">
{{alert.msg}}
</alert>
<input type="text" id="username" ng-model="username" placeholder="Username"/>
<input type="password" id="password" ng-model="password" placeholder="Password"/>
<button type="button" id="loginBtn" class="btn btn-primary" ng-model="loginModel" ng-click="login()" ui-keypress="{13:'keypressLogin($event)'}">
Login
</button>
</div>
My login controller:
ClutchControllers.controller("LoginController", [
'$scope',
'$http',
'$location',
'$cookieStore',
'Auth',
function($scope, $http, $location, $cookieStore, Auth) {
// Redirect if already logged in
if(Auth.isLoggedIn()) {
$location.path('/dashboard');
}
$scope.alerts = [];
$scope.closeAlert = function(index) {
$scope.alerts.splice(index, 1);
}
$scope.login = function() {
Auth.login({
username: $scope.username,
password: $scope.password
}, function(err, user) {
if(err) {
console.log(err);
$scope.alerts = [err];
} else {
console.log(user);
console.log(Auth.isLoggedIn());
//this this if you want to change the URL and add it to the history stack
$location.path('/dashboard');
}
});
}
$scope.keypressLogin = function($event) {
console.log($event);
console.log($scope.username);
}
}
]);
And finally, my app routing:
angular.module('myApp', [
'ngCookies',
'ui.utils',
'ui.bootstrap',
'ui.utils',
'clutch.services',
'clutch.controllers'
])
.config(['$routeProvider', '$httpProvider', function($routeProvider, $httpProvider) {
$routeProvider
.when('/login', {
controller: "LoginController",
templateUrl: "partials/login.html",
auth: false
})
.when('/dashboard', {
controller: "DashboardController",
templateUrl: "partials/dashboard.html",
auth: true
})
.otherwise({ redirect: "/login" });
}]);
ClutchControllers = angular.module('clutch.controllers', ['ui.bootstrap']);
ClutchServices = angular.module('clutch.services', ['ngResource']);
Just a thought, why would you want to use ui-keypress. IMHO using a form is better solution in this case. Consider this...
<form ng-submit="login()">
<input type="text"/>
<input type="password"/>
<button type="submit">Login</button>
</form>
Taking a wild guess -- you've got the ui-keypress attribute on your button and not your two input tags..
Took me a bit to reproduce in jsfiddle w/ all your dependencies: http://jsfiddle.net/tuv45/