AngularJS ui-router giriş kimlik doğrulaması


376

AngularJS için yeniyim ve aşağıdaki senaryoda açısal "ui-router" ı nasıl kullanabileceğim konusunda biraz kafam karıştı:

İki bölümden oluşan bir web uygulaması yapıyorum. İlk bölüm giriş ve kayıt görünümlerinin bulunduğu ana sayfadır ve ikinci bölüm gösterge tablosudur (başarılı girişten sonra).

Bir oluşturduk index.htmlonun açısal uygulaması ve ev bölümü için ui-routerkoluna yapılandırma /loginve /signupgörünümleri ve başka bir dosya var dashboard.htmlonun app ile pano bölümü için ui-routerbirçok alt görünümleri işlemek için yapılandırma.

Şimdi kontrol paneli bölümünü bitirdim ve iki bölümü farklı açısal uygulamalarıyla nasıl birleştireceğinizi bilmiyorum. Ev uygulamasına, gösterge tablosu uygulamasına yeniden yönlendirmesini nasıl söyleyebilirim?


1
Bazı kodları bizimle paylaşabilir misiniz?
Chancho

6
@Chancho Bence kodla ilgili değil, gerçekten hangi kodu paylaşmalıyım bilmiyorum.
Ahmed Hashem

Evet, lütfen kodu paylaşın, çok genel bir soru ...
Alireza

Yanıtlar:


607

Daha güzel bir demo yapma ve bu hizmetlerden bazılarını kullanılabilir bir modül haline getirme sürecindeyim, ama işte buradayım. Bu, bazı uyarılar etrafında çalışmak için karmaşık bir süreçtir, bu yüzden orada durun. Bunu birkaç parçaya bölmeniz gerekecek.

Bu şişeye bir bakın .

İlk olarak, kullanıcının kimliğini saklamak için bir hizmete ihtiyacınız vardır. Buna ben diyorum principal. Kullanıcının oturum açıp açmadığını kontrol edebilir ve istek üzerine kullanıcının kimliği hakkında temel bilgileri temsil eden bir nesneyi çözebilir. Bu, ihtiyacınız olan her şey olabilir, ancak temel bilgiler bir görünen ad, bir kullanıcı adı, muhtemelen bir e-posta ve bir kullanıcının ait olduğu roller olacaktır (bu, uygulamanız için geçerliyse). Müdür ayrıca rol kontrolleri yapma yöntemlerine de sahiptir.

.factory('principal', ['$q', '$http', '$timeout',
  function($q, $http, $timeout) {
    var _identity = undefined,
      _authenticated = false;

    return {
      isIdentityResolved: function() {
        return angular.isDefined(_identity);
      },
      isAuthenticated: function() {
        return _authenticated;
      },
      isInRole: function(role) {
        if (!_authenticated || !_identity.roles) return false;

        return _identity.roles.indexOf(role) != -1;
      },
      isInAnyRole: function(roles) {
        if (!_authenticated || !_identity.roles) return false;

        for (var i = 0; i < roles.length; i++) {
          if (this.isInRole(roles[i])) return true;
        }

        return false;
      },
      authenticate: function(identity) {
        _identity = identity;
        _authenticated = identity != null;
      },
      identity: function(force) {
        var deferred = $q.defer();

        if (force === true) _identity = undefined;

        // check and see if we have retrieved the 
        // identity data from the server. if we have, 
        // reuse it by immediately resolving
        if (angular.isDefined(_identity)) {
          deferred.resolve(_identity);

          return deferred.promise;
        }

        // otherwise, retrieve the identity data from the
        // server, update the identity object, and then 
        // resolve.
        //           $http.get('/svc/account/identity', 
        //                     { ignoreErrors: true })
        //                .success(function(data) {
        //                    _identity = data;
        //                    _authenticated = true;
        //                    deferred.resolve(_identity);
        //                })
        //                .error(function () {
        //                    _identity = null;
        //                    _authenticated = false;
        //                    deferred.resolve(_identity);
        //                });

        // for the sake of the demo, fake the lookup
        // by using a timeout to create a valid
        // fake identity. in reality,  you'll want 
        // something more like the $http request
        // commented out above. in this example, we fake 
        // looking up to find the user is
        // not logged in
        var self = this;
        $timeout(function() {
          self.authenticate(null);
          deferred.resolve(_identity);
        }, 1000);

        return deferred.promise;
      }
    };
  }
])

İkincisi, kullanıcının gitmek istediği durumu kontrol eden, oturum açtıklarından emin olan (gerekirse; oturum açma, şifre sıfırlama vb. İçin gerekli değildir) bir rol hizmetine ihtiyacınız vardır ve ardından bir rol kontrolü yapar (uygulamanız buna ihtiyaç duyar). Kimlik doğrulaması yapılmazsa, oturum açma sayfasına gönderin. Kimlik doğruları doğrulanmış ancak bir rol denetiminde başarısız olmuşlarsa, erişim reddedilen bir sayfaya gönderin. Ben buna hizmet diyorum authorization.

.factory('authorization', ['$rootScope', '$state', 'principal',
  function($rootScope, $state, principal) {
    return {
      authorize: function() {
        return principal.identity()
          .then(function() {
            var isAuthenticated = principal.isAuthenticated();

            if ($rootScope.toState.data.roles
                && $rootScope.toState
                             .data.roles.length > 0 
                && !principal.isInAnyRole(
                   $rootScope.toState.data.roles))
            {
              if (isAuthenticated) {
                  // user is signed in but not
                  // authorized for desired state
                  $state.go('accessdenied');
              } else {
                // user is not authenticated. Stow
                // the state they wanted before you
                // send them to the sign-in state, so
                // you can return them when you're done
                $rootScope.returnToState
                    = $rootScope.toState;
                $rootScope.returnToStateParams
                    = $rootScope.toStateParams;

                // now, send them to the signin state
                // so they can log in
                $state.go('signin');
              }
            }
          });
      }
    };
  }
])

Şimdi tüm is dinlemesini yapmak gerekir ui-router's $stateChangeStart. Bu size mevcut durumu, gitmek istedikleri durumu inceleme ve yetkilendirme kontrolünüzü ekleme şansı verir. Başarısız olursa, rota geçişini iptal edebilir veya farklı bir rotaya değiştirebilirsiniz.

.run(['$rootScope', '$state', '$stateParams', 
      'authorization', 'principal',
    function($rootScope, $state, $stateParams, 
             authorization, principal)
{
      $rootScope.$on('$stateChangeStart', 
          function(event, toState, toStateParams)
      {
        // track the state the user wants to go to; 
        // authorization service needs this
        $rootScope.toState = toState;
        $rootScope.toStateParams = toStateParams;
        // if the principal is resolved, do an 
        // authorization check immediately. otherwise,
        // it'll be done when the state it resolved.
        if (principal.isIdentityResolved()) 
            authorization.authorize();
      });
    }
  ]);

Bir kullanıcının kimliğini izlemeyle ilgili zor kısım, daha önce kimlik doğrulaması yaptıysanız (örneğin, önceki bir oturumdan sonra sayfayı ziyaret edip bir çerezde bir kimlik bilgisi jetonu kaydettiyseniz veya belki de sayfayı yenilediğinizde) veya bir bağlantıdan URL'ye düştü). Çalışma şekli nedeniyle, ui-routerkimlik doğrulaması kontrol etmeden önce kimliğinizi bir kez çözmeniz gerekir. Bunu resolvedurum yapılandırmanızdaki seçeneği kullanarak yapabilirsiniz . Tüm eyaletlerin miras aldığı site için bir ana eyaletim var, bu da yöneticiyi başka bir şey gerçekleşmeden çözülmeye zorluyor.

$stateProvider.state('site', {
  'abstract': true,
  resolve: {
    authorize: ['authorization',
      function(authorization) {
        return authorization.authorize();
      }
    ]
  },
  template: '<div ui-view />'
})

Burada başka bir sorun daha var ... resolvesadece bir kez çağrılıyor. Kimlik arama vaadiniz tamamlandığında, çözüm temsilcisini tekrar çalıştırmaz. Bu nedenle, kimlik doğrulama kontrollerinizi iki yerde yapmak zorundayız: bir kez kimlik vaatlerinize çözümlenerek resolve, uygulamanızın ilk kez yüklenmesini kapsar ve bir kez $stateChangeStartde çözünürlük yapıldığı takdirde, eyaletler arasında dolaştığınız her zamanı kapsar.

Tamam, şimdiye kadar ne yaptık?

  1. Kullanıcının oturum açıp açmadığını uygulamanın ne zaman yüklediğini kontrol ederiz.
  2. Giriş yapan kullanıcı hakkındaki bilgileri takip ediyoruz.
  3. Kullanıcının oturum açmasını gerektiren durumlar için oturum açma durumuna yönlendiriyoruz.
  4. Erişme yetkileri yoksa, bunları erişim reddedildi durumuna yönlendiririz.
  5. Giriş yapmaları gerekiyorsa, kullanıcıları istedikleri orijinal duruma geri yönlendirmek için bir mekanizmamız var.
  6. Bir kullanıcının oturumunu kapatabiliriz (kimlik doğrulama biletinizi yöneten herhangi bir istemci veya sunucu koduyla uyumlu olarak bağlanması gerekir).
  7. Biz yok oturum açma sayfasına geri onların tarayıcınızı yeniden veya bir bağlantıyı açılan her zaman kullanıcıları göndermek gerekiyor.

Buradan nereye gidiyoruz? Eh, sen Oturum açmayı gerektiren bölgelere halinde devletleri organize edebilirsiniz. Sen ekleyerek kimlik doğrulaması / yetkili kullanıcıları gerektirebilirsiniz dataile roles(eğer devralma kullanmak isterseniz veya bunların bir ebeveyn), bu ülkelere. Burada, bir kaynağı Yöneticilerle kısıtlıyoruz:

.state('restricted', {
    parent: 'site',
    url: '/restricted',
    data: {
      roles: ['Admin']
    },
    views: {
      'content@': {
        templateUrl: 'restricted.html'
      }
    }
  })

Artık kullanıcıların bir rotaya nelere erişebileceğini eyalet bazında kontrol edebilirsiniz. Başka endişeleriniz var mı? Giriş yapılıp yapılmadığına bağlı olarak görünümün yalnızca bir bölümünü değiştirebilir misiniz? Sorun değil. Bir şablonu veya öğeyi koşullu olarak görüntülemenin çeşitli yollarından herhangi biriyle principal.isAuthenticated()veya hatta kullanın principal.isInRole().

İlk olarak, principalbir denetleyiciye veya herhangi bir şeye enjekte edin ve görünümünüzde kolayca kullanabilmeniz için kapsama yapıştırın:

.scope('HomeCtrl', ['$scope', 'principal', 
    function($scope, principal)
{
  $scope.principal = principal;
});

Bir öğeyi gösterme veya gizleme:

<div ng-show="principal.isAuthenticated()">
   I'm logged in
</div>
<div ng-hide="principal.isAuthenticated()">
  I'm not logged in
</div>

Vb, vb. Her neyse, örnek uygulamanızda, ana sayfa için kimliği doğrulanmamış kullanıcıların uğramasına izin verecek bir durumunuz olur. Oturum açma veya kaydolma durumlarına bağlantıları olabilir veya bu formların o sayfada yerleşik olmasını sağlayabilirler. Sana nasıl uyarsa.

Gösterge tablosu sayfalarının tümü, kullanıcıların oturum açmasını ve örneğin bir Userrol üyesi olmasını gerektiren bir durumdan miras alabilir . Tartıştığımız tüm yetkilendirme konuları oradan akacaktır.


28
Teşekkürler, bu gerçekten kendi kodumu bir araya getirmeme yardımcı oldu. Yan notta, sonsuz bir yönlendirme döngüsü (UI Router hatası) alırsanız, $location.pathyerine deneyin $state.go.
jvannistelrooy

2
Bu harika bir cevap ve bana çok yardımcı oldu. Denetleyicimde user = principal ayarladığımda ve şu anda oturum açmış olan kullanıcıların adını almak için bence user.identity (). Name'i aramaya çalıştığımda yalnızca söz verilen nesneyi alıyorum {then: fn, catch: fn, nihayet :} döndü, gerçek _identity nesnesi değil. Ben user.identity.then (fn (kullanıcı)) kullanırsanız kullanıcı nesnesi alabilirsiniz ama bu görünüm için bir sürü kod gibi görünüyor bir şey eksik mi?
Mark

4
Ir1sh @ ben denetleyicisi ilk kimliğini çözümlemek istiyorum ve atamak $scope.useriçin de thenişlevi. Yine de usergörüşlerinize başvurabilirsiniz ; çözüldüğünde görünüm güncellenecektir.
moribvndvs

2
@HackedByChinese Bence demo artık çalışmıyor.
Blowsie

7
@jvannistelrooy go () ile ilgili problemlerim vardı, ama böyle bir noop işlevini çağırdıktan sonra içine koyduktan sonra $q.when(angular.noop).then(function(){$state.go('myState'), her şey beklendiği gibi çalışıyor. Ben ararsam $state.gobaşka durum geçiş tamamlanmaz ise, o zaman değil iş (Ben neden iş olmaz nedeni olduğunu düşünüyorum) olacaktır.
Sebastian

120

Bence şimdiye kadar yayınlanan çözümler gereksiz derecede karmaşık. Daha basit bir yol var. Dokümantasyonuui-router dinlemek diyor $locationChangeSuccessve kullanım $urlRouter.sync()durum geçişini kontrol etmek, bunu durdurmak, devam ettirmek. Ama bu bile işe yaramıyor.

Ancak, burada iki basit alternatif var. Birini seçin:

Çözüm 1: Dinleme $locationChangeSuccess

Dinleyebilir $locationChangeSuccessve bazı mantık, hatta eşzamansız mantık bile gerçekleştirebilirsiniz. Bu mantığa dayanarak, işlevin tanımsız olarak dönmesine izin verebilirsiniz; bu durum durum geçişinin normal şekilde devam etmesine neden olabilir veya $state.go('logInPage')kullanıcının kimliği doğrulanması gerekiyorsa yapabilirsiniz . İşte bir örnek:

angular.module('App', ['ui.router'])

// In the run phase of your Angular application  
.run(function($rootScope, user, $state) {

  // Listen to '$locationChangeSuccess', not '$stateChangeStart'
  $rootScope.$on('$locationChangeSuccess', function() {
    user
      .logIn()
      .catch(function() {
        // log-in promise failed. Redirect to log-in page.
        $state.go('logInPage')
      })
  })
})

Bunun aslında hedef durumun yüklenmesini engellemediğini, ancak kullanıcının yetkisiz olması durumunda oturum açma sayfasına yönlendirdiğini unutmayın. Zaten gerçek koruma sunucuda olduğu için sorun değil.

Çözüm 2: Durumu Kullanma resolve

Bu çözümde, ui-routerçözüm özelliğini kullanırsınız .

Temel olarak resolve, kullanıcının kimliği doğrulanmadıysa sözünü reddeder ve ardından oturum açma sayfasına yönlendirirsiniz.

İşte böyle:

angular.module('App', ['ui.router'])

.config(
  function($stateProvider) {
    $stateProvider
      .state('logInPage', {
        url: '/logInPage',
        templateUrl: 'sections/logInPage.html',
        controller: 'logInPageCtrl',
      })
      .state('myProtectedContent', {
        url: '/myProtectedContent',
        templateUrl: 'sections/myProtectedContent.html',
        controller: 'myProtectedContentCtrl',
        resolve: { authenticate: authenticate }
      })
      .state('alsoProtectedContent', {
        url: '/alsoProtectedContent',
        templateUrl: 'sections/alsoProtectedContent.html',
        controller: 'alsoProtectedContentCtrl',
        resolve: { authenticate: authenticate }
      })

    function authenticate($q, user, $state, $timeout) {
      if (user.isAuthenticated()) {
        // Resolve the promise successfully
        return $q.when()
      } else {
        // The next bit of code is asynchronously tricky.

        $timeout(function() {
          // This code runs after the authentication promise has been rejected.
          // Go to the log-in page
          $state.go('logInPage')
        })

        // Reject the authentication promise to prevent the state from loading
        return $q.reject()
      }
    }
  }
)

İlk çözümün aksine, bu çözüm aslında hedef durumun yüklenmesini önler.


6
@FredLackey, kimliği doğrulanmamış kullanıcının bulunduğunu söylüyor state A. Gitmek için bir bağlantıyı tıklarlar protected state Bancak yönlendirmek istersiniz logInPage. Hayır ise $timeout, ui-routertüm durum geçişlerini durduracak, böylece kullanıcı sıkışacaktır state A. $timeoutVerir ui-routerilk başlangıç geçişi önlemek için protected state Bkararlılık reddedildiği için ve Bu işlem tamamlandıktan sonra, yönlendirir logInPage.
MK Safi

authenticateFonksiyon aslında nerede denir?
CodyBugstein

@Imray authenticateişlevi bir parametre olarak iletilir ui-router. Kendiniz olarak adlandırmanıza gerek yok. ui-routerdiyor.
MK Safi

Neden '$ stateChangeStart' yerine '$ locationChangeSuccess' kullanıyorsunuz?
Draex_

@ PeterDraexDräxler Çoğunlukla belgeleri takip ediyordum. Kullanarak herhangi bir fark fark ettiniz $stateChangeStartmi?
MK Safi

42

En kolay çözüm, kullanıcının kimliği doğrulanmadığında durum değişikliğini kullanmak $stateChangeStartve event.preventDefault()iptal etmek ve onu giriş sayfası olan kimlik doğrulama durumuna yönlendirmektir .

angular
  .module('myApp', [
    'ui.router',
  ])
    .run(['$rootScope', 'User', '$state',
    function ($rootScope, User, $state) {
      $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
        if (toState.name !== 'auth' && !User.authenticaded()) {
          event.preventDefault();
          $state.go('auth');
        }
      });
    }]
  );

6
User.authenticaded () bir zaman uyumsuz çağrı ise, bu işe yarayacağını sanmıyorum. Bu herkesin peşinde olduğu kutsal kâse. Örneğin, "oturum açma" dışındaki her durum güvenliyse, herhangi bir durum yüklemeden ÖNCE kullanıcının hala kimlik doğrulaması yapıldığını onaylamak istiyorum . Kullanımı sadece bir kez çözümlendikleri için berbat olur ve alt durumların yüklenmesini önlemek için, çözümü HER ÇOCUĞA enjekte etmeniz gerekir .
Jason

authenticated benim durumumda bir zaman uyumsuz çağrı değil: `this.authenticaded = function () {if (this.currentAccountID! == null) {return true; } yanlış döndür; }; `
sebest

Şuna göre: stackoverflow.com/a/38374313/849829 , 'run' hizmetlerin çok üzerinde gelir ve dolayısıyla problemler. Yerel depolamanın doğrulanmış durum için kontrol edilmesi iyi bir yaklaşım gibi görünmektedir.
Deepak Thomas

22

serviceKimlik doğrulama işlemini (ve depolamasını) işleyecek bir ihtiyacınız olduğunu düşünüyorum .

Bu hizmette bazı temel yöntemlere ihtiyacınız olacak:

  • isAuthenticated()
  • login()
  • logout()
  • vb ...

Bu hizmet, her modülün kontrolörlerine enjekte edilmelidir:

  • Gösterge tablosu bölümünüzde, kullanıcının kimliğinin doğrulanıp doğrulanmadığını ( service.isAuthenticated()yöntem) kontrol etmek için bu hizmeti kullanın . değilse, / login adresine yönlendirin
  • Giriş bölümünde, service.login()yönteminizi kullanarak kullanıcının kimliğini doğrulamak için form verilerini kullanmanız yeterlidir

Bu davranış için iyi ve sağlam bir örnek, proje açısal uygulaması ve özellikle harika HTTP Kimlik Doğrulama Önleme Modülü'ne dayanan güvenlik modülüdür.

Bu yardımcı olur umarım


21

Bu işlemi çok kolay hale getirmek için bu modülü oluşturdum

Şöyle şeyler yapabilirsiniz:

$routeProvider
  .state('secret',
    {
      ...
      permissions: {
        only: ['admin', 'god']
      }
    });

Veya ayrıca

$routeProvider
  .state('userpanel',
    {
      ...
      permissions: {
        except: ['not-logged-in']
      }
    });

Yepyeni ama kontrol etmeye değer!

https://github.com/Narzerus/angular-permission


2
ne zaman kaynak düzenleme ve 'admin' kaldırma beni durdurmak için || 'tanrı' ve devam ediyor mu?
Pogrindis

12
Yetkilendirme gerektiren herhangi bir veri isteğinin de sunucuda doğrulanmasını umuyorum.
Ben Ripley

24
Bu güvenlik için değildir, istemci taraflı yetkilendirme asla değerleri her zaman değiştirebileceğinizden değildir. Sunucu tarafından gelen yanıtları bile kesip "yetkili" olarak değerlendirebilirsiniz. İstemci tarafındaki izinler / yetkilendirme noktası, kullanıcının ux amaçları için yasaklı şeyler yapmasına izin vermekten kaçınmaktır. Örneğin, yalnızca yönetici tarafından yapılan bir eylemi gerçekleştiriyorsanız, kullanıcı istemciyi sunucuya kısıtlı bir istek göndermesine izin vermek için kötü bir şekilde kandırsa bile, sunucu yine de 401 yanıtı döndürür. Bu elbette ki her zaman api'nin sorumluluğundadır @BenRipley gerçekten de
Rafael Vidaurre

3
Rafael sorusuna büyük cevap. Api'leri her zaman koruyun, çünkü ön uç neredeyse tersine çevrilebilir, en taklit edilebilir şeydir.
Frankie Loscavio

1
Tarihle ilgili bu sorun bir süredir @Bohdan'da çözüldü. Ui-router ekstralarıyla bile güvenle kullanabilirsiniz.
masterspambot

16

Ui router 1.0.0.X ile çalışan başka bir çözümü paylaşmak istedim

Bildiğiniz gibi, stateChangeStart ve stateChangeSuccess artık kullanımdan kaldırıldı. https://github.com/angular-ui/ui-router/issues/2655

Bunun yerine $ geçişlerini kullanmalısınız http://angular-ui.github.io/ui-router/1.0.0-alpha.1/interfaces/transition.ihookregistry.html

Ben böyle başardım:

İlk olarak ve bazı yararlı işlevlere sahip AuthService var

angular.module('myApp')

        .factory('AuthService',
                ['$http', '$cookies', '$rootScope',
                    function ($http, $cookies, $rootScope) {
                        var service = {};

                        // Authenticates throug a rest service
                        service.authenticate = function (username, password, callback) {

                            $http.post('api/login', {username: username, password: password})
                                    .success(function (response) {
                                        callback(response);
                                    });
                        };

                        // Creates a cookie and set the Authorization header
                        service.setCredentials = function (response) {
                            $rootScope.globals = response.token;

                            $http.defaults.headers.common['Authorization'] = 'Bearer ' + response.token;
                            $cookies.put('globals', $rootScope.globals);
                        };

                        // Checks if it's authenticated
                        service.isAuthenticated = function() {
                            return !($cookies.get('globals') === undefined);
                        };

                        // Clear credentials when logout
                        service.clearCredentials = function () {
                            $rootScope.globals = undefined;
                            $cookies.remove('globals');
                            $http.defaults.headers.common.Authorization = 'Bearer ';
                        };

                        return service;
                    }]);

Sonra bu yapılandırma var:

angular.module('myApp', [
    'ui.router',
    'ngCookies'
])
        .config(['$stateProvider', '$urlRouterProvider',
            function ($stateProvider, $urlRouterProvider) {
                $urlRouterProvider.otherwise('/resumen');
                $stateProvider
                        .state("dashboard", {
                            url: "/dashboard",
                            templateUrl: "partials/dashboard.html",
                            controller: "dashCtrl",
                            data: {
                                authRequired: true
                            }
                        })
                        .state("login", {
                            url: "/login",
                            templateUrl: "partials/login.html",
                            controller: "loginController"
                        })
            }])

        .run(['$rootScope', '$transitions', '$state', '$cookies', '$http', 'AuthService',
            function ($rootScope, $transitions, $state, $cookies, $http, AuthService) {

                // keep user logged in after page refresh
                $rootScope.globals = $cookies.get('globals') || {};
                $http.defaults.headers.common['Authorization'] = 'Bearer ' + $rootScope.globals;

                $transitions.onStart({
                    to: function (state) {
                        return state.data != null && state.data.authRequired === true;
                    }
                }, function () {
                    if (!AuthService.isAuthenticated()) {
                        return $state.target("login");
                    }
                });
            }]);

Kullandığımı görebiliyorsun

data: {
   authRequired: true
}

yalnızca kimliği doğrulanmışsa erişilebilir durumu işaretlemek için.

sonra .run üzerinde otantikleştirilmiş durumu kontrol etmek için geçişleri kullanıyorum

$transitions.onStart({
    to: function (state) {
        return state.data != null && state.data.authRequired === true;
    }
}, function () {
    if (!AuthService.isAuthenticated()) {
        return $state.target("login");
    }
});

Ben $ geçişler belgelerinde bulunan bazı kodu kullanarak bu örnek oluşturmak. UI yönlendirici ile oldukça yeniyim ama işe yarıyor.

Umarım herkese yardımcı olabilir.


Bu, yeni yönlendiriciyi kullananlar için mükemmeldir. Teşekkürler!
mtro

5

Sonsuz yönlendirme döngüsünden nasıl çıktık ve $state.gobunun yerine hala$location.path

if('401' !== toState.name) {
  if (principal.isIdentityResolved()) authorization.authorize();
}

1
Adres çubuğunda yukarıda açıklanan kabul edilen cevap / kurulumu kullanırken neden artık url'yi ve tüm parçaları ve sorgu dizesi parametrelerini göstermediğini bilen var mı? Bu adres çubuğunu uyguladığımızdan, artık uygulamamızın yer işareti koyulmasına izin vermiyor.
Frankie Loscavio

1
Bunun mevcut cevaplardan biri hakkında bir yorum olması gerekmez mi? OP'de böyle bir kod olmadığı için ve bunun hangi cevaba / hangi koda atıfta bulunduğu bile net değil
TJ

3

Başka bir çözüm var: Bu çözüm, yalnızca oturum açtığınızda göstermek istediğiniz içeriğe sahip olduğunuzda mükemmel çalışır. Oturum açıp açmadığınızı ve beyaz liste yollarının değil yolunu kontrol ettiğiniz bir kural tanımlayın.

$urlRouterProvider.rule(function ($injector, $location) {
   var UserService = $injector.get('UserService');
   var path = $location.path(), normalized = path.toLowerCase();

   if (!UserService.isLoggedIn() && path.indexOf('login') === -1) {
     $location.path('/login/signin');
   }
});

Örneğimde, giriş yapmadığımı ve yönlendirmek istediğim mevcut rotanın `/ login'in bir parçası olmadığını soruyorum, çünkü beyaz liste rotalarım aşağıdaki

/login/signup // registering new user
/login/signin // login to app

bu yüzden bu iki rotaya anında erişebiliyorum ve online olursanız diğer her rota kontrol edilecek.

İşte giriş modülü için tüm yönlendirme dosyam

export default (
  $stateProvider,
  $locationProvider,
  $urlRouterProvider
) => {

  $stateProvider.state('login', {
    parent: 'app',
    url: '/login',
    abstract: true,
    template: '<ui-view></ui-view>'
  })

  $stateProvider.state('signin', {
    parent: 'login',
    url: '/signin',
    template: '<login-signin-directive></login-signin-directive>'
  });

  $stateProvider.state('lock', {
    parent: 'login',
    url: '/lock',
    template: '<login-lock-directive></login-lock-directive>'
  });

  $stateProvider.state('signup', {
    parent: 'login',
    url: '/signup',
    template: '<login-signup-directive></login-signup-directive>'
  });

  $urlRouterProvider.rule(function ($injector, $location) {
    var UserService = $injector.get('UserService');
    var path = $location.path();

    if (!UserService.isLoggedIn() && path.indexOf('login') === -1) {
         $location.path('/login/signin');
    }
  });

  $urlRouterProvider.otherwise('/error/not-found');
}

() => { /* code */ } ES6 sözdizimidir, bunun yerine kullanın function() { /* code */ }


3

$ Http Interceptor kullanın

Bir $ http önleme aracı kullanarak başlıkları Arka Uç'a veya başka bir yolla gönderebilir ve çeklerinizi bu şekilde yapabilirsiniz.

$ Http önleme hakkında harika makale

Misal:

$httpProvider.interceptors.push(function ($q) {
        return {
            'response': function (response) {

                // TODO Create check for user authentication. With every request send "headers" or do some other check
                return response;
            },
            'responseError': function (reject) {

                // Forbidden
                if(reject.status == 403) {
                    console.log('This page is forbidden.');
                    window.location = '/';
                // Unauthorized
                } else if(reject.status == 401) {
                    console.log("You're not authorized to view this page.");
                    window.location = '/';
                }

                return $q.reject(reject);
            }
        };
    });

Bunu .config veya .run işlevinize koyun.


2

Öncelikle, bazı uygulama kimlik doğrulama durumu fikri olan denetleyicilerinize enjekte edebileceğiniz bir hizmete ihtiyacınız olacak. Yerel depolama ile kimlik doğrulama ayrıntılarının kalıcı olması, ona yaklaşmanın iyi bir yoludur.

Ardından, durum değişmeden hemen önce yetkilendirme durumunu kontrol etmeniz gerekir. Uygulamanızda kimliği doğrulanması gereken bazı sayfalar ve olmayanlar olduğu için, kimlik doğrulamasını kontrol eden bir üst yol oluşturun ve aynı gerektiren diğer tüm sayfalar bu üst öğenin alt öğesi olsun.

Son olarak, şu anda oturum açmış olduğunuz kullanıcının belirli işlemleri yapıp yapamayacağını anlamanız için bir yol bulmanız gerekir. Bu, kimlik doğrulama hizmetinize bir 'can' işlevi eklenerek gerçekleştirilebilir. Can iki parametre alır: - eylem - gerekli - (örn. 'Manage_dashboards' veya 'create_new_dashboard') - nesne - isteğe bağlı - üzerinde çalıştırılan nesne. Örneğin, bir gösterge tablosu nesneniz varsa, gösterge tablosu.ownerId === logedInUser.id'in olup olmadığını kontrol etmek isteyebilirsiniz. (Tabii ki, istemciden iletilen bilgilere asla güvenilmemelidir ve veritabanınıza yazmadan önce bunu sunucuda her zaman doğrulamanız gerekir).

angular.module('myApp', ['ngStorage']).config([
   '$stateProvider',
function(
   $stateProvider
) {
   $stateProvider
     .state('home', {...}) //not authed
     .state('sign-up', {...}) //not authed
     .state('login', {...}) //not authed
     .state('authed', {...}) //authed, make all authed states children
     .state('authed.dashboard', {...})
}])
.service('context', [
   '$localStorage',
function(
   $localStorage
) {
   var _user = $localStorage.get('user');
   return {
      getUser: function() {
         return _user;
      },
      authed: function() {
         return (_user !== null);
      },
      // server should return some kind of token so the app 
      // can continue to load authenticated content without having to
      // re-authenticate each time
      login: function() {
         return $http.post('/login.json').then(function(reply) {
            if (reply.authenticated === true) {
               $localStorage.set(_userKey, reply.user);
            }
         });
      },
      // this request should expire that token, rendering it useless
      // for requests outside of this session
      logout: function() {
         return $http.post('logout.json').then(function(reply) {
            if (reply.authenticated === true) {
               $localStorage.set(_userKey, reply.user);
            }
         });
      },
      can: function(action, object) {
         if (!this.authed()) {
            return false;
         }

         var user = this.getUser();

         if (user && user.type === 'admin') {
             return true;
         }

         switch(action) {
            case 'manage_dashboards':
               return (user.type === 'manager');
         }

         return false;


      }
   }
}])
.controller('AuthCtrl', [
   'context', 
   '$scope', 
function(
   context, 
   $scope
) {
   $scope.$root.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
      //only require auth if we're moving to another authed page
      if (toState && toState.name.indexOf('authed') > -1) {
         requireAuth();
      }
   });

   function requireAuth() {
      if (!context.authed()) {
         $state.go('login');
      }
   }
}]

** YASAL UYARI: Yukarıdaki kod yalancı koddur ve garanti verilmez **

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.