天天看點

AngularJS 如何做身份驗證

權限的設計中比較常見的就是rbac基于角色的通路控制,基本思想是,對系統操作的各種權限不是直接授予具體的使用者,而是在使用者集合與權限集合之間建立一個角色集合。每一種角色對應一組相應的權限。

    一旦使用者被配置設定了适當的角色後,該使用者就擁有此角色的所有操作權限。這樣做的好處是,不必在每次建立使用者時都進行配置設定權限的操作,隻要配置設定使用者相應的角色即可,而且角色的權限變更比使用者的權限變更要少得多,這樣将簡化使用者的權限管理,減少系統的開銷。

    1. ui處理(根據使用者擁有的權限,判斷頁面上的一些内容是否顯示)

    2. 路由處理(當使用者通路一個它沒有權限通路的url時,跳轉到一個錯誤提示的頁面)

    3. http請求處理(當我們發送一個資料請求,如果傳回的status是401或者403,則通常重定向到一個錯誤提示的頁面)

如何實作?

    首先需要在angular啟動之前就擷取到目前使用者的所有的 permissions,然後比較優雅的方式是通過一個service存放這個映射關系.對于ui處理一個頁面上的内容是否根據權限進行顯示,我們應該通 過一個directive來實作.當處理完這些,我們還需要在添加一個路由時額外為其添加一個"permission"屬性,并為其指派表明擁有哪些權限 的角色可以跳轉這個url,然後通過angular監聽routechangestart事件來進行目前使用者是否擁有此url通路權限的校驗.最後還需要 一個http攔截器監控當一個請求傳回的status是401或者403時,跳轉頁面到一個錯誤提示頁面.大緻上的工作就是這些,看起來有些多,其實一個個來還是挺好處理的.

傳回401,執行loginctrl,傳回403執行permissionctrl。

在angular運作之前擷取到permission的映射關系

    angular項目通過ng-app啟動,但是一些情況下我們是希望 angular項目的啟動在我們的控制之中.比如現在這種情況下,我就希望能擷取到目前登入使用者的所有permission映射關系後,再啟動 angular的app.幸運的是angular本身提供了這種方式,也就是angular.bootstrap().

AngularJS 如何做身份驗證

var permissionlist;  

angular.element(document).ready(function() {  

  $.get('/api/userpermission', function(data) {  

    permissionlist = data;  

    angular.bootstrap(document, ['app']);  

  });  

});  

進一步使用上面的代碼可以将擷取到的映射關系放入一個service作為全局變量來使用.

AngularJS 如何做身份驗證

// app.js  

var app = angular.module('myapp', []), permissionlist;  

app.run(function(permissions) {  

  permissions.setpermissions(permissionlist)  

// common_service.js  

angular.module('myapp')  

  .factory('permissions', function ($rootscope) {  

    var permissionlist;  

    return {  

      setpermissions: function(permissions) {  

        permissionlist = permissions;  

        $rootscope.$broadcast('permissionschanged')  

      }  

   };  

 在取得目前使用者的權限集合後,我們将這個集合存檔到對應的一個service中,然後又做了2件事:

    (1) 将permissions存放到factory變量中,使之一直處于記憶體中,實作全局變量的作用,但卻沒有污染命名空間.

    (2) 通過$broadcast廣播事件,當權限發生變更的時候.

1如何确定ui元件的依據權限進行顯隐

    這裡我們需要自己編寫一個directive,它會依據權限關系來進行顯示或者隐藏元素.

AngularJS 如何做身份驗證

<!-- if the user has edit permission the show a link -->  

<div has-permission='edit'>  

  <a href="/#/courses/{{ id }}/edit"> {{ name }}</a>  

</div>  

<!-- if the user doesn't have edit permission then show text only (note the "!" before "edit") -->  

<div has-permission='!edit'>  

  {{ name }}  

 這裡看到了比較理想的情況是通關一個has-permission屬性校驗permission的name,如果目前使用者有則顯示,沒有則隐藏.

AngularJS 如何做身份驗證

angular.module('myapp').directive('haspermission', function(permissions) {  

  return {  

    link: function(scope, element, attrs) {  

      if(!_.isstring(attrs.haspermission))  

        throw "haspermission value must be a string";  

      var value = attrs.haspermission.trim();  

      var notpermissionflag = value[0] === '!';  

      if(notpermissionflag) {  

        value = value.slice(1).trim();  

      function togglevisibilitybasedonpermission() {  

        var haspermission = permissions.haspermission(value);  

        if(haspermission && !notpermissionflag || !haspermission && notpermissionflag)  

          element.show();  

        else  

          element.hide();  

      togglevisibilitybasedonpermission();  

      scope.$on('permissionschanged', togglevisibilitybasedonpermission);  

    }  

  };  

 擴充一下之前的factory:

AngularJS 如何做身份驗證

      },  

      haspermission: function (permission) {  

        permission = permission.trim();  

        return _.some(permissionlist, function(item) {  

          if(_.isstring(item.name))  

            return item.name.trim() === permission  

        });  

 2路由上的依權限通路

    這一部分的實作的思路是這樣: 當我們定義一個路由的時候增加一個permission的屬性,屬性的值就是有哪些權限才能通路目前url.然後通過routechangestart事 件一直監聽url變化.每次變化url的時候,去校驗目前要跳轉的url是否符合條件,然後決定是跳轉成功還是跳轉到錯誤的提示頁面.

AngularJS 如何做身份驗證

app.config(function ($routeprovider) {  

  $routeprovider  

    .when('/', {  

      templateurl: 'views/viewcourses.html',  

      controller: 'viewcoursesctrl'  

    })  

    .when('/unauthorized', {  

      templateurl: 'views/error.html',  

      controller: 'errorctrl'  

    .when('/courses/:id/edit', {  

      templateurl: 'views/editcourses.html',  

      controller: 'editcourses',  

      permission: 'edit'  

    });  

 maincontroller.js 或者 indexcontroller.js (總之是父層controller)

AngularJS 如何做身份驗證

app.controller('mainappctrl', function($scope, $location, permissions) {  

  $scope.$on('$routechangestart', function(scope, next, current) {  

    var permission = next.$$route.permission;  

    if(_.isstring(permission) && !permissions.haspermission(permission))  

      $location.path('/unauthorized');  

這裡依然用到了之前寫的haspermission,這些東西都是高度可複用的.這樣就搞定了,在每次view的route跳轉前,在父容器的controller中判斷一些它到底有沒有跳轉的權限即可.

3http請求處理

    這個應該相對來說好處理一點,思想的思路也很簡單.因為angular應用推薦的是restful風格的借口,是以對于http協定的使用很清晰.對于請求傳回的status code如果是401或者403則表示沒有權限,就跳轉到對應的錯誤提示頁面即可.

    當然我們不可能每個請求都去手動校驗轉發一次,是以肯定需要一個總的filter.代碼如下:

AngularJS 如何做身份驗證

  .config(function($httpprovider) {  

    $httpprovider.responseinterceptors.push('securityinterceptor');  

  })  

  .provider('securityinterceptor', function() {  

    this.$get = function($location, $q) {  

      return function(promise) {  

        return promise.then(null, function(response) {  

          if(response.status === 403 || response.status === 401) {  

            $location.path('/unauthorized');  

          }  

          return $q.reject(response);  

      };  

    };