如何在路由前检查令牌的有效性?

Posted

技术标签:

【中文标题】如何在路由前检查令牌的有效性?【英文标题】:How to check the token validity before routing? 【发布时间】:2019-09-22 15:33:47 【问题描述】:

我正在后端设置一个带有 angularjs 路由 (ngRoute) 和 expressjs 的 Web 应用程序。

我有一个疑问,我不明白为什么检查用户是否登录的“标准”解决方案是在本地存储中查找令牌。我的意思是,任何时候都不会检查其有效性。用户可以在浏览器中手动插入令牌。

我知道当用户尝试执行操作时服务器端会意识到用户没有登录,但我认为手动插入令牌的用户仍然可以访问一些私有路由(例如,创建表单)。

我不知道如何解决这个问题。 我试图向服务器询问应用程序运行的有效性。问题是程序在第一次路由之前没有等待promise。

var appRun = function($rootScope, $location, $route, $timeout, API_URL, auth, authToken) 
    //running...
    auth.getProfile();

    $rootScope.$on('$locationChangeStart', function(event, next, current) 
      var routeUrl = '/' + current.replace(API_URL, '').split('/')[1];
      routeUrl = getRouteParams(routeUrl);

      var routeObj = $route.routes[routeUrl];
      var userProfile = authToken.isAuthenticated(), redirectPath;

      //not valid route
      if (!routeObj) 
        redirectPath = getRedirectPath(userProfile);
        $location.path(redirectPath);
      

      //restricted route
      else if (routeObj.restricted && userProfile !== 'LOGGED') 
        redirectPath = getRedirectPath(userProfile);
        $location.path(redirectPath);
      
      ...
   

//In auth service...
 ...

 getProfile: function() 
        if (!(!!authToken.getToken()))  
            return authToken.setUserProfile('FORBIDDEN') 
        

        //if the token exists check it
        return $http.get(API_URL + '/auth')
          .then(function(response) 
            authToken.setUserProfile(response.data.status);
            return response;
          )
          .catch(function(error) 
            return authToken.setUserProfile(error.data.message);
          );
      

  ...

【问题讨论】:

那又怎样?黑客无法访问任何敏感信息,也无法通过在浏览器中显示表单来造成任何伤害。而且您无需显示任何表单即可向服务器发送 HTTP 请求。重要的是你在服务器端做什么。这就是您必须确保请求来自经过身份验证的用户、具有有效令牌的用户以及有权执行该请求的用户。客户端的令牌检查只是为了符合人体工程学的目的:您不希望普通用户转到他们无论如何都无法成功提交的表单。 你说得对!谢谢你的回答。 【参考方案1】:

不要转换被拒绝的承诺

为什么 *** 上有这么多示例将拒绝的承诺转换为已履行的承诺?

//In auth service...
 ...

 getProfile: function() 
        if (!(!!authToken.getToken()))  
            ̶ ̶r̶e̶t̶u̶r̶n̶ ̶a̶u̶t̶h̶T̶o̶k̶e̶n̶.̶s̶e̶t̶U̶s̶e̶r̶P̶r̶o̶f̶i̶l̶e̶(̶'̶F̶O̶R̶B̶I̶D̶D̶E̶N̶'̶)̶ 
             authToken.setUserProfile('FORBIDDEN') 
             return $q.reject("FORBIDDEN - No token");
        

        //if the token exists check it
        return $http.get(API_URL + '/auth')
          .then(function(response) 
            authToken.setUserProfile(response.data.status);
            return response;
          )
          .catch(function(error) 
            ̶r̶e̶t̶u̶r̶n̶ ̶a̶u̶t̶h̶T̶o̶k̶e̶n̶.̶s̶e̶t̶U̶s̶e̶r̶P̶r̶o̶f̶i̶l̶e̶(̶e̶r̶r̶o̶r̶.̶d̶a̶t̶a̶.̶m̶e̶s̶s̶a̶g̶e̶)̶;̶
            authToken.setUserProfile(error.data.message);
            //RE-THROW rejected promises
            throw error;
          );
      

当一个 promise 错误处理程序 returns 一个值时,$q 服务转换 被拒绝 的promise 为一个履行 的promise。要保留拒绝状态,re-throw 一个原因或返回一个 rejected 承诺。

看起来有人使用了一个名为 getProfile 的函数并对其进行了破解以添加副作用。他们没有使用 Profile 承诺,而是放弃承诺并使用副作用。

返回被拒绝的promise到路由解析函数

可以在路由解析函数中使用返回被拒绝的承诺的函数来中止加载路由:

app.config(function($routeProvider, $locationProvider) 
    $routeProvider
    .when('/Book/:bookId', 
        templateUrl: 'book.html',
        controller: 'BookController',
        resolve: 
            profile: function(auth) 
                return auth.getProfile();
            
        
    )
)

auth.getProfile() 函数返回一个rejected promise 时,ngRoute 路由器中止视图的加载并广播$routeChangeError 事件。

有关详细信息,请参阅

AngularJS ngRoute $routeProvider API Reference You're Missing the Point of Promises

【讨论】:

以上是关于如何在路由前检查令牌的有效性?的主要内容,如果未能解决你的问题,请参考以下文章

我应该在哪里以及如何在passportjs中检查访问令牌的有效性

检查 cookie 中 JWT 令牌的有效性时如何避免不必要的 API 调用

Angular 8:如何在没有刷新令牌的情况下刷新令牌

node js jwt如何将令牌传递给其他路由以稍后检查登录的用户信息

如何检查JWT令牌剩余有效时间golang

从 startup.cs 检查令牌有效性