How to bring role based view with UI Router in Angular JS? - angularjs

I am developing a SPA (Single Page Application) with Angular JS and using "UI Router" for routing and using Spring MVC framework for back-end.
I would like to bring the user role based view in the application as we have different user roles in application.
What is the best way to do this?
Is there any way to retrieve the user role from server check it in the ui route before state changes?

You could pass roles through the data attribute and the check the user access on the $stateChangeStart event. This would off course require you to implement users with user roles.
Pass the role restriction as custom data to state object (https://github.com/angular-ui/ui-router/wiki#user-content-attach-custom-data-to-state-objects)
$stateProvider
.state('admin', {
url: '/admin',
data: {
roles: ['ROLE_ADMIN']
}
})
Then in the .run function do a check on the $stateChangeStart event if current user has said role and if so allow the route change, if not send user to some kinda access denied page (or just prevent state change).
.run(function($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function (event, toState, toStateParams) {
// Check if current user has group access
if(!AuthService.userHasRole(toStateParams.roles)) {
$state.go('accessdenied');
}
})
})
There would be quite a bit of work off course to get this working. Setting up users/roles/auth etc. Will leave that to you. JHipster (https://jhipster.github.io/) has a pretty solid auth, access, user with user roles implementation. The backend is in Java though. But the Angular implementation is rock solid.

One way I am exploring is simply putting the various views on the page wrapped in ng-if's and checking the userRole.role(a global value) to determine which state to view.
However, there has to be(or should) be a way to do it relatively easily in UI-Router I would think...
Then again, I wam building this on a sharepoint site, so I don't have to worry about top level access rights as we set those on Sharepoint itself. Anyone who can actualy view the page will be 1 of 5 types of userRoles, I simply have to get the role and then show the proper view based on that role

Related

Angular Router - Using abstract state to access service

Using mean.js:
I have a large application that is divided by say, offices. Each office accesses the same application in the same way, but employees of an office may only access information pertaining to that office. Company administrators may access the app fully, switching between office contexts. The caveat is that there are no user accounts (no login/auth) for office employees, only admin accounts for the administrators.
I'm exploring doing it in the following way:
I created an access module with a service that stores the office context, passing it to the backend when making API calls. This is set upon application startup from config files.
This is well and good, but I need to allow the administrators to switch office contexts. I use a link <a ui-sref="Context({ officeID: 'x' }) (in the navbar dropdown, so accessible from every state) to access the angular router:
.state('Context', {
url: '/Context/:officeID',
controller: 'ContextController',
controllerAs: 'vm'
});
This passes the officeID to the ContextController, which would set the ContextService.officeID variable. At this time, I believe I would make an api call from the ContextController to refresh the current state's data to reflect the current context. Not sure how to do that.
I feel that I have some options here, which I am unsure how to implement:
I can make the Context state abstract, and every other state a child, but that seems bulky. If this is correct, how do I tell the current state to refresh it's data?
I could enter the Context state, set the ContextService.officeID, and immediately redirect back to the previous state, which upon entering, should make an api call using the new context. If this is correct, how do I properly perform that redirect?
I could scrap how this is being done entirely, but I don't know where I would start. Any advice is welcome.
I figured out something that feels a bit more elegant.
I still use the Context route. I've included the ContextService in all of my angular modules, and call it when the context needs to be set.
I tried to redirect using $location.path(...), which was a major headache. Using $state.go($state.previous.state.name) works a treat.
Even better, if you use routes that depend on resolves, you can further redirect using $state.go($state.previous.state.name, $stateParams);

MEAN Stack - pass variables from html view to ng-controller

I have developed a profile page which contains several modules such as, let's say : personal info and friends.
Each modules is a ng-controller which makes database calls but I would like to be able to pass the id of the user of whom the profile is being displayed so that database calls are dynamics and retrieve data related to this user.
How I am supposed to do that?
Thanks in advance,
Manuel
* Clarification *
I am using express.js which handles authentication and session management (with Passport).
Once the user is logged in he reaches the "/profile" page.
I didn't particularly want to handle routing on several sides so I decided to handle all routing on Node side. So I have created routes for get and post calls.
Now, when the user arrives on "/profile" I would like the different modules (personnal info, friends, etc.) to update based on the person connected.
I managed to do non-dynamic call :
app.controller('UserInfo', [
'$scope', '$http',
function($scope, $http) {
$http.get("/api/users/info/1")
.then(function(response) {
$scope.user = response.data.local;
});
}
]);
But this doesn't depend on the context. So I would like now to create get calls the same way but being able to pass the id (or any other proper way) of the user to retreive his data.
Would you have any recommendation as to how to proceed? Any link to tutorials on how to handle this in multi-page MEAN application? Most of documents I found on the internet are related to single-page applications and don't answer my need.
Thanks!
If your UI handle who am I, you will get some security breach.
Your server need to know who is connected. (with a cookie or something like that).
Here is an exemple : https://blog.nodejitsu.com/sessions-and-cookies-in-node/

creating external links to my angularJS app

so i'm trying to create a public/external link that can be generated and shared to anyone for people to get to a specific state of my angularJS app.
I am using $stateProvider to manage states on the app. but i need a part of the app to be open to the public. i.e a particular state open to the public such that as soon as they hit that the url e.g mydoamin/post it gives them access to that state alone. for example
.state("post", {
url: "/post",
controller: "postController",
templateUrl: "templates/post.html",
})
My app currently user $stateChangeStart to check between state transitions but is setup to block any unauthenticated user. so if anyone that is not logged in tries to get to a state it kicks them back to the login state which is the default '/'.
.state("login", {
url: "/",
controller: "LoginController",
templateUrl: "templates/login.html",
})
I know i could just give each state a value probably 'authenticated' and set it to true or false for each state and check the toState on $stateChangeStart if 'authenticated' is false and grant access based on that but i need to know if its a good idea and how to securely implement it.
How would you do this?. thanks in advance for any reply/suggestion.
For 'securing' the UI, i.e. hide some pages from unauthorized users, use ui-state router's resolve parameter. See this question for more info. Put a 'resolve' on the states that need authentication, and leave it out for the public pages.
However it is important to understand that any security measure that is implemented client-side, is never fully secure. Anyone can have access to any page, including the ones that require authentication. All it takes for them is to open dev tools and alter the JavaScript. That's why you should properly handle authorization at API level. This way, even if a malicious user can see a hidden page (i.e. he can browse to it and see the html), he won't be able to see any data that was fetched from the API.

Creating Separate UI for different Roles

I have two roles in my application say Customer and Provider and I want to create separate UI for them after they are authenticated, keeping login screen same and have a radio button that says "I'm a Customer" and "I'm a Provider", this also be same during registration.
I'm looking for a better approach, I have no Idea how to start with.
I already have a an existing UI interface for customers, but now requirement is for "Provider" Interface. So that customer can interact , send requirements, do query directly with provider. currently Customer application send these request by email.
First of all you should detect and define which components are going to be shown for both and which components are only for one or other. After you know exactly how your app will be, angularjs provides a lot of native directives for managing different cases.
Take a look at:
ng-if
ng-switch
ng-hide
ng-show
Those will be of great help for you. But always remember to manage security server side, web apps can be easily manipulated and if you are working with roles and different permissions take this as a must have.
BTW, consider using angularjs $routeProvider in some of the following ways for managing permissions:
$routeProvider.when('/admin/users', {
controller: 'userListCtrl',
templateUrl: 'js/modules/admin/html/users.tmpl.html',
access: {
requiresLogin: true,
requiredPermissions: ['Admin', 'UserManager'],
permissionType: 'AtLeastOne'
});
OR
$routeProvider.
when('/admin', {
templateUrl: 'Your template url',
controller: 'AdminController',
permission: 'AccessAdministration',
resolve: {
permissionList: function (permissionService) { return permissionService.getPermissions(); }
}
})

AngularJs authorization layout

I am building a large application with Web API and AngularJs. I built the secure web api with authentication and claim-based authorizations. One requirement is that different users can view different modules on the same template.
I am new to AngularJs. I did the authentication in client side with the tokens. Also, in web api, I created a service to get all the permission given a user id. The response is a list of resource(contoller)/action(method) pairs. How do I implement the correct layout based on authorization rules on client side? Does that solely rely on web api permissions response and show/hide (ng-hide/ng-show) content based on the permissions?
Is this a good approach? What other modules/directives do I need to look into? Such as the loader for not loading the nested route until user request the parent route.
To add complexity, this site also need to work in bi-lingual. I think ng-translate. I mentioned this because it may open up another discussion on whether this may favor MVC instead of AngularJs. But the preference is Angular if the above two problem can be resolved.
All the authentication & authorisation & validation should be done server-side. You can adjust the user interface based on the roles/claims the server tells the browser the current user has.
One way to do this is to create something like a roles/userprofile controller, which will respond with a list of roles the current user has. On the client side you’ll probably want something you can inject everywhere, so you’re able to determine user interface behaviour.
myApp.factory(‘myUser’, function(Roles, $q) {
// Create a promise to inform other folks when we’re done.
var defer = $q.defer();
// For this example I’m using ngResource
Role.query({
/*
No params — let the server figure out who you ‘really’ are.
Depending on WebApi configuration this might just be
as simple as this.User (in context of the controller).
*/
}, function(roles) {
var user = {
roles: roles,
isInRole: function(role) {
return user.roles.indexOf(role) !== -1;
}
};
defer.resolve(user);
});
return defer;
});
Because the factory above is returning a promise we can enforce that myUser is resolved before a certain route/controller instance is created. One little trick I use is to gather all my route definitions in one object, loop through them with an angular.forEach and add a resolve.myUser property to each of them. You can use this to pre-load/initialize other stuff too.
Now inject the myUser anywhere you like:
myApp.controller(‘MyController’, function($scope, myUser) {
// Expose it on the current scope
$scope.myUser = myUser;
});
… and in your markup …
<div class=“my-content-thingy”>
<p>Lorem del ipsum …</p>
<button class=“btn” ng-if=“myUser.isInRole(‘content-editor’)”></button>
</div>
Note: You’ll probably want to use ng-if and not ng-show; the latter keeps the element in the DOM.
Just keep in mind that you don’t authenticate anything on the client side; that all done server side. A simple way is to place Authorize attributes on the appropriate controller actions.
Hope this helps.
A proper approach is to build AngularJS routing configuration as per Authorization on the server. This should be build just after the user is authorized and before the AngularJS app is initialized. That way the authorized user sees a "complete" app based on his roles etc. Using ng-show/ng-hide is not a good way to do it. Also each view should be doing only one thing. So load separate views based on the task that needs to be completed.
Regarding multi language support, this is independent of Authorization. Some time ago, I wrote a custom AngularJS filter that used the jQuery i18next plugin. It was a pretty simple implementation.
However you can now use https://github.com/i18next/ng-i18next
(Sorry for misunderstanding the problem).
I think that using ng-hide/show is not much of a problem. At the end of the day, the user does not have access to the data. I think it should rely on the api permissions + show/hide of presentation. Depends on the complexity you want... You can use MVC with angularjs since it's a large application.

Resources