Just started using angular and I'm trying to learn as fast as I can. I'm relatively new to SPA's so please bear with me and feel free to tell me if what I want to do is not feasible. What I'm currently stuck on now, is how do I protect my routes when using the ui-router?
What do I want to do?
There are routes that I don't want non-logged in users to access.
For example, /home and /login are okay for anonymous users.
/dashboard should only be for those that are logged in.
I want it so if a user tries to access /dashboard in the future without being logged in, they are not able to.
What have I already tried?
I have tried using the angular-permission module found here: https://github.com/Narzerus/angular-permission
The problem is..I'm not quite sure how to use it (nor if I'm using it properly).
What is currently happening?
In my login controller, once a user submits their username and password it makes a /POST to my web-sever. Once it gets the result, (regardless of what it is for the moment) I've got it redirecting to /dashboard.
Right now nothing should be getting to the /dashboard because no permissions have been set, yet I am (incorrectly) allowed to see the dashboard. I can both (1) successfully be redirected to the dashboard without permission and (2) access /dashboard without permission.
What does my code look like right now?
controllers.js
var controllers = angular.module('controllers',[])
// Login Controller -- This handles the login page that the user can enter
// enter his username & password.
controllers.controller('loginController', function($scope, $state,$location, LoginService){
$scope.email = "";
$scope.password = ""
$scope.login = function(){
var data = ({email:"test", password: "ayylmao"})
LoginService.login(data).then(function(res){
console.log(res);
})
.catch(function(err){
console.log("ERROR!");
console.log(err);
$state.go('dashboard')
})
}
})
app.js
//Definition: The parent module
var myApp = angular.module('clipboardApp', ['services','controllers', 'permission','ui.router']);
//Code below taken from the angular-permission docs.
angular
.module('fooModule', ['permission', 'user'])
.run(function (PermissionStore, User) {
// Define anonymous permission)
PermissionStore
.definePermission('anonymous', function (stateParams) {
// If the returned value is *truthy* then the user has the permission, otherwise they don't.
//True indicates anonymous.
//Always returning true to indicate that it's anonymous
return true;
});
});
//This will be serving as the router.
myApp.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
//By default go
$urlRouterProvider.otherwise('/home');
//Views are
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'views/home.html',
})
.state('login', {
url: '/login',
templateUrl: 'views/login.html',
controller: 'loginController'
})
.state('dashboard', {
url: '/dashboard',
templateUrl: 'views/dashboard.html',
controller: 'dashboardController',
data: {
permissions: {
except: ['anonymous'],
redirectTo: 'login'
}
}
});
});
Here is a working example with secured routes. In this example any state start with app. will go via the auth interceptor. $transitions.onBefore hook can be use as follows to satisfy your requirement.
.run(($transitions, $state, $injector) => {
$transitions.onBefore({
to: 'app.**'
}, () => {
const $window = $injector.get('$window');
if (!$window.sessionStorage.getItem('user')) {
return $state.target('login', $state.transition.params());
}
return true
});
});
https://plnkr.co/edit/ZCN2hB34mMEmBJulyaAJ?p=info
Related
I have email verification state defined as below, which redirects the state to account if the user is logged in and otherwise it opens up, but the thing is with dynamic params of verification url.
$stateProvider
.state('verification', {
url: '/verification/:email/:token',
templateUrl: 'verification/verification.tpl.html',
controller: 'VerificationCtrl',
title: 'Verification',
resolve: {
UnauthenticatedUser: ['$q', '$state', 'securityAuthorization', function($q, $state, securityAuthorization){
var promise = securityAuthorization.requireUnauthenticatedUser()
.catch(function(){
// user is authenticated, redirect
$state.go('account.dashboard');
return $q.reject();
});
return promise;
}]
}
});
In this case it should redirect to account.dashboard(/account/dashboard), but it bounce back to this url(/verification/:email/:token) after that.
But if I put the url as /verification only then it works normally the way it is supposed to and redirect to account.dashboard.
Can someone suggest where I am going wrong
So I have this very strange error: I want to check if a user is login when enter a state and redirect them back to SignIn page if they are not. So in my config I have:
.state('home', {
cache: false,
abstract: true,
url: "/home",
templateUrl: "app/home/home.html",
onEnter: function($state, MyFirebaseService) {
// check session
var userId = MyFirebaseService.LoginUserId();
if (!userId) {
$state.go('auth.signin')
};
}
})
So I type in http://localhost:8100/#/home/courses to go into courses page without login, everything work perfectly. User got redirect back to auth.signin view. But when I type in the address bar again http://localhost:8100/#/home/courses, it throw 4 errors:
TypeError: Cannot read property '#' of null
TypeError: Cannot read property 'auth-signin#auth' of null
TypeError: Cannot read property 'auth-signup#auth' of null
My signin and signup are in an abstract view call auth. Why is that and how to fix it?
I personnaly perform those actions of authenticatio ncontrol on .run( with event catcher :
.run([
'$rootScope','authService','$q',
function($rootScope, authService,q) {
$rootScope.$on('$stateChangeStart', function(event, next, current) {
// YOUR CONTROL & REDIRECT
});
}]);
If you add some authorisation role control for instance on ui-router, for instance:
.state('home', {
url: "/home",
templateUrl: "includes/pages/homePage.html",
resolve : {
authorizedRoles : function(){ return [ USER_ROLES['su'],
USER_ROLES['user'],
USER_ROLES['admin'],
USER_ROLES['skyadmin'],
USER_ROLES['skyuser'],
USER_ROLES['skysu']
] }
}
})
You can easily check into $stateChangeStart with var authorizedRoles = next.resolve.authorizedRoles(); and compare them with your user roles
I'm trying to redirect unauthorized people when they first enter my website via a url;
eg: example.com/#/order should be redirected to example.com/#/auth, this includes when they first visit the webpage and also navigating inbetween states.
Currently I have an abstract parent state of /order and /auth which have resolves that check for authentication and redirect otherwise. I also have a watch on the $stateChangeStart event to do the same thing.
The code for when you initially load the page works correctly, it will redirect if you visit /order/restaurant without being logged in, however if I'm on the url /auth/login I can change my url to /order/resturant and it will redirect me successful but the view will not update. I will still be able to see the /order/resturant page but the resolve and page changes were hit. Why does this happen? I've attempted to use $rootScope.$apply() without success as well.
My code is as follows for the parent states:
// Authentication Urls
.state('auth', {
url: '/auth',
templateUrl: 'modules/auth/auth.html',
abstract: true
})
// Order Urls
.state('order', {
url: '/order',
templateUrl: 'modules/order/order.html',
abstract: true
})
and my code to watch the stateChange
.run(['$rootScope', '$location', 'Auth', function($rootScope, $state, Auth) {
$rootScope.$on('$stateChangeStart', function(event, toState) {
var stateName = toState.name
console.log('State start')
if (!stateName.match(/auth/) && !Auth.isLoggedIn) {
console.log('User is not visiting auth and isn\'t logged in, redirecting....')
$state.go('auth.login')
} else if (Auth.isLoggedIn && stateName.match(/auth/)) {
console.log('User is logged in and is on the auth page, redirecting....')
$state.go('order.resturant')
}
})
}])
Looking at the documentation here (http://github.com/angular-ui/ui-router/wiki#state-change-events) you should cancel the navigation by calling event.preventDefault() before performing your new transition.
I have a MEAN stack app generated with the Yeoman Generator Angular Fullstack generator. You should only have access to the site by logging in.
The repo for ensureLoggedIn is here
While logged out, if I try to navigate to '/products' I'm redirected to '/login' just fine. However, I'm having an issue redirecting users who aren't logged in when the url is '/' or even 'localhost:9000' without the slash.
If I'm not logged in, and at the login screen, and I modify '/login' to just '/' or '' I'm sent to "main" in AngularJS and treated as logged in(I'm assuming because it recognizes the session?) and able to click links through to '/products' or '/users'.
My current routes.js looks like this:
/**
* Main application routes
*/
'use strict';
var errors = require('./components/errors');
var auth = require('./controllers/auth');
var passport = require('passport');
var ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn;
module.exports = function(app) {
// Insert routes below
// All undefined asset or api routes should return a 404
app.route('/:url(api|auth|components|app|bower_components|assets)/*').get(errors[404]);
app.route('/login').get(auth.login).post(auth.loginUser);
app.route('/logout').get(auth.logout);
// All other routes should redirect to the index.html
app.all('*', ensureLoggedIn('/login'));
app.route('/*').get(function(req, res) {
res.sendfile(app.get('appPath') + '/index.html');
});
};
I've also tried this with the routes:
app.route('/*').get(function(req, res) {
res.sendfile(app.get('appPath') + '/index.html');
});
Which seems to have the same behavior as placing ensureLoggedIn in app.all.
Here's a snippet of my routing on the Angular side, which uses ui-router:
.config ($stateProvider, $urlRouterProvider, $locationProvider) ->
$httpProvider.interceptors.push('httpInterceptor')
$urlRouterProvider
.otherwise '/'
$stateProvider
.state 'main',
url: '/'
templateUrl: 'app/views/main/main.html'
controller: 'MainCtrl'
.state 'users',
url: '/users'
templateUrl: 'app/views/users/index.html'
controller: 'UsersController'
As I said, the redirect works fine on '/users'. I'm not sure if this is a routing issue or auth issue. Auth should be fine, since clicking logout does take you to login screen and restricts access, but doesn't restrict access to the '/' route.
For the views, the login.jade is actually on the server side and the form is processed there. Except for a 404.jade, all other views are on the client-side and served using ui-router.
I feel like I'm overlooking something basic. Or just don't fully understand how this is working together. Any help would be great.
EDIT:
One thing I tried was changing the routing before app.route('login'):
app.route('/')
.get(function(req, res) {
res.render('login');
});
And changing ui-router url for main from '/' to '/main'.
This still grabbed index.html from angular and logged me in, so it didn't work. I also tried res.redirect to login in routes.js and it didn't redirect.
This is the code I use for handling authentication. It is a hack but I didn't find a better way when I needed to code it. Also the routes defined in the system varied user to user so I couldn't define them in the normal config stage. This may help with your issue though.
$routeProvider
.when("/login", { templateUrl: "/view/account/login.html", controller: Login })
.when("/forgottenpassword", { templateUrl: "/view/account/forgottenpassword.html", controller: ForgottenPassword })
.otherwise({ redirectTo: "login" });
This basically only allows access to 2 views. Once someone authenticates successfully I rebuild the routing table with the new valid views. Any invalid navigation goes to the login view.
I do this through a hack though so it might not be the best implementation angularjs wise. I do this by keeping a reference to $routeProvider on the window object then use $routeProvider as normal when you have a successful logon.
The original $routeProvider provided in angular also needs a public method to clear the existing routes before adding new ones.
After
var routes = {};
Add
this.ClearRoutes = function ()
{
routes = {};
}
Example usage after successful logon
$routeProvider.ClearRoutes();
$routeProvider
.when("/home", { templateUrl: "/view/home.html", controller: Home })
.when("/logoff", { templateUrl: "/view/account/logoff.html", controller: Logoff })
.otherwise({ redirectTo: "home" });
I am trying to create a route that clears the users session and redirects them back to the root homepage.
.config(function config( $routeProvider, $stateProvider ) {
$routeProvider.
when('/logout', {resolve: {redirect: function(Session){
Session.clear();
return "/home";
}}});
I'm obviously doing something wrong here, as calling
$location.path("/logout");
... ignores the function and redirects back to the default route. I've tried adding console.log statements to the function to see if it is being called.
Am I using the redirect function incorrectly?
Have you considered putting your logout logic in a separate controller? Would be a little cleaner, more robust, & make redirection more straightforward. Like so:
function LogoutController($location) {
Session.clear();
$location.path('/home');
}
The your route is:
when('/logout', {
template: '', //A template or templateUrl is required by AngularJS, even if your controller always redirects.
controller: 'LogoutController'
}).
I had the same issue and what I did instead was create a logout function in my navigationController that gets hit when the URL is clicked
<li>Log Out</li>
And in my navigationController:
$scope.logout = function () {
localStorage.clearAll();
window.location = '/logout';
};
I'm running ASP.NET behind Angular so I needed the browser (not angular) to route to /logout which is mapped in ASP.NET config (does a few other session clean ups and redirects to authentication app)
Hope this helps
just store the $sessionStorage (username) then delete the the $sessionStorage (username) ..
$scope.logout = function(){
delete $sessionStorage.sessname; //sessname is get sessionStorage username
$location.path('/login');
};
help me for this link:https://stackoverflow.com/questions/36056745/angularjs-click-logout-button-to-clear-sessionstorage-again-and-again-go-back-to
I use this approach
$routeProvider
.when('/logout', {
resolve: {
logout: ['authService', function (authService) {
authService.clear(true);
}]
}
})