The most recent project is to use angular to do a single page application, but because the user has different roles (administrators, editors, general financial staff, etc.), it requires different roles to access control.
Because of the rich experience of backend access control, only the implementation of front-end access control is recorded here. Please note that the front end can only do display control! and can not guarantee security, so the backend is sure to do access control!
Role-based access control requires two levels of access control:
- Controls the jump of page routing, users who do not have permission to jump to the specified URL
- page element display control, users without corresponding permissions cannot see the element
But until then, we have one more important thing to do.
Store user Information
The first thing we have to do is not with access control, first of all we have to save the user information. Includes the user's basic information, such as user name, real name, and user role. Here is the data structure:
user = {
Username: "",
Realname: "",
Role: ""
}
Store the entire user at the time of storage, but where is it? Given the need to be accessible on any page, the first reaction is stored in the Rootscope, but we should try to avoid using rootscope, and in addition, we can store in the top controller or global constant, both of which can be But their problem is that once the page is refreshed, it doesn't work ($rootScope too). Considering the life cycle of the user variable should be the same as session, so I used the sessionstorage.
When you create a controller, you need to join $sessionstorage:
App.controller (' controller ', [' $sessionStorage ', function ($sessionStorage) {}]);
After the login succeeds, the user is stored in the Sessionstorage:
$sessionStorage. user = user;
OK, then you can get the user information through the $sessionstorage.
user = $sessionStorage. User;
Control the jump of page routing
Below we begin to implement the 1th: Control page Route jump.
To do the 1th is easier, angular route changes will trigger the $statechangestart event (I use Stateprovider, so listen to Statechangestart, if the route or location, Should listen to their corresponding events, listening to this event, in which according to the Access URL and user role for the right to judge, such as login can be done in the judgment, access to the URL to login directly to the login interface.
First, write a auth service for permission authentication:
/** * role-based access Control/app.service ("auth", ["$http", "$sessionStorage", Function ($http, $sessionStorage) {var roles = [];
The role table from the backend database//URL mapping table from the backend, the structure is {"Role": ["/page1", "/page2" ...]}
var urlpermissions = {}; To the back end get (function () {//Here for testing convenience, direct assignment, below also for example for the purpose, as simple as possible roles = ["admin", "user"] Urlpermissions = {//admin
Access to the page "admin": ["*"],//Normal users can access all the interfaces under the page path (login, registration, etc.) and the System home page "user": ["page.*", "App.index", "App.detail"]
}
})(); function Convertstate (state) {return State.replace (".", "\\\.").
Replace ("*", ". *");
return {//whether there is a permission to access a URL isaccessurl:function (URL) {var user = $sessionStorage. User; for (var = roles) {if (user.role.toLowerCase () = = Roles[role].tolowercase ()) {Console.log (urlpermissions[ Roles[role]]) {var regx = eval ("/" +convertstate Urlpermissions[roles[r
Ole]][i]) + "/"); Console.log (regx+ "" + URL) if (regx.test (URL)) {
return true;
}}} return false;
}
}
}])
Roles is a role that is fetched from the background; Urlpermissions is the list of URLs that each role corresponds to, and is retrieved from the background, and can be configured through the background. This way, each time a new role is added, we can dynamically configure access rights for it.
The most important thing is the Isaccessurl method, after passing in the URL, Isaccessurl first obtains the user information through the $sessionstorage, obtains the user role, then sees the user role in the role table, if in the role table, sees this role to have the access URL the permission. When we configure it in the background, we specify the state directly, but if there is no wildcard, then each page must write a URL, so, add the wildcard features, and then the URL list of each URL into a regular expression, and then to verify that the configuration is a lot more flexible.
The last is to listen for event $statechangestart in run:
App.run (["$rootScope", "$state", "auth", "$sessionStorage", Function ($rootScope, $state, auth, $sessionStorage) {
$rootScope. $on (' $stateChangeStart ', function (event, tostate, Toparams, FromState, fromparams) {
//Routing access Control
if ( tostate.name!= "Page.login" &&!auth.isaccessurl (tostate.name) {
//See if login required:
var user = $ Sessionstorage.user;
if (user = = null) {
event.preventdefault ();
$state. Go ("Page.login");
return;
}
Event.preventdefault ();
$state. Go ("Page.error");}})
OK, now we have the access control of the URL.
Display control of page elements
As for the 2nd, my solution is a custom directive, and here is an example:
<div zg-access= "Test_access" ></div>
Note that the incoming is not a role, but a privilege. Because the user role can be dynamically expanded, if the role is written here to access this element, then each new role will be a big problem, because you have to modify the code one by one. The following is the code for the custom Directive zg-access:
/** * Element level access control instruction/app.directive ("Zgaccess", Function ($sessionStorage, $http) {var roles = [];//role Var Elempermi Ssions = {}; The role Element permission mapping table, such as {"Roles": {"Search"}},role has this searching permission//Background fetch (function () {//) for simplicity, here directly generates roles = ["admin", "user", "visit
or "];
Elempermission = {"admin": ["*"], "user": ["SEARCH"], "visitor": []}) ();
Console.log ("zg-access"); Return {restrict: ' A ', compile:function (element, attr) {//initially invisible State none, also disabled disbaled and available OK, a total of three states Var level
= "None";
Console.log (attr) if (attr && attr["Zgaccesslevel"]) {level = attr["Zgaccesslevel"];
Switch (level) {case ' none ': element.hide ();
Case "Disabled": element.attr ("Disabled", "");
Break
//Get element permissions var access = attr["zgaccess"];
Upload this permission to the backend database (function () {//upload}) ();
return function (scope, Element) {//To determine whether the user has permission for var user = $sessionStorage. User; if (user==null| | Angular.equalS ({}, user)) {user = {};
User.role = "Visitor";
var role = User.role.toLowerCase ();
Console.log (roles);
for (var i in roles) {var tmp = roles[i].tolowercase ();
if (role = = tmp) {tmp = Elempermission[role];
Console.log (TMP) for (Var j in Tmp) {Console.log (tmp[j]+ "" +access);
if (access.tolowercase () = = Tmp[j].tolowercase ()) {element.removeattr ("disabled");
Element.show ();
}
}
}
}
};
}
}
})
Zgaccesslevel is an attribute that controls the level, and if none (default is None), the element is not displayed, and if it is disbaled, the element is unavailable (such as the button is unavailable).
The following is an example of an element:
<button ng-click= "" zg-access= "SEARCH" zg-access-level= "disabled" >Search</button>
At this point, if you are logged in as the admin role or the user role, the search button will not be available.
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.