nodejs和angular app使用JWT发送401 Unauthorized和200 OK

时间:2017-09-04 12:26:44

标签: javascript angularjs node.js jwt

当我在表单上单击注册时,从我可以理解的角度来看,在节点服务器可以授权JWT并发送200 OK之前,将URL设置为/ profile(受保护的路由)。我不确定如何防止这种情况。

即使我在本地存储中有令牌,受保护的路由也会返回并且是未经授权的错误。因此,即使发送了200 OK响应,如果我重新加载/ profile路由,它仍将获得401.

路线:

const path = require('path');
const Company = require('./models/app');
const User = require('./models/users');
const jwt = require('express-jwt');
let auth = jwt({
  secret: process.env.CONFIG_SR,
  requestProperty: 'payload'
});

module.exports = function(app , passport) {
    function profileCheck(req , res , next) {
        if(!req.payload._id) {
            res.status(401).json({
              "message" : "UnauthorizedError: private profile"
            });
        } else {
            User.findById(req.payload._id)
                .exec(function(err, user) {
                    res.status(200).json(user);
                });
        }
    }
    app.get('/' , function(req , res) {
        res.sendFile(path.join(__dirname , '../public' , 'index.html'));
    });
    app.get('/login' , function(req , res) {
        res.sendFile(path.join(__dirname , '../public' , 'login.html'));
    });
    app.post('/api/login' , function(req, res) {
        passport.authenticate('local' , function(err, user, info) {
            if(err) {
                return res.json({
                    'message': err
                });
            } if(user) {
                token = user.generateJwt();
                res.status(200);
                res.json({
                    "token" : token
                });
            } else {
                return res.json({
                    'message': 'User not found'
                });
            }
        })(req, res);
    });
    app.get('/register' , function(req , res) {
        res.sendFile(path.join(__dirname , '../public' , 'register.html'));
    });
    app.post('/api/register' , function(req, res) {
        User.findOne({'local.email': req.body.email}, function(err, user) {
            if(err) {
                return res.json({
                    'message': err
                });
            }
            if(user) {
                return res.json({
                    'message': 'User already exists'
                });
            } else {
                let newUser = new User();

                newUser.local.email = req.body.email;
                newUser.local.name = req.body.name;
                newUser.local.password = newUser.setPassword(req.body.password);

                newUser.save(function(err) {
                    // passport.authenticate('local',{ session: false }, function(req, res) {});
                    var token;
                    token = newUser.generateJwt();
                    res.status(200);
                    res.json({
                        'token': token
                    });
                });
            }
        });
    });
    app.get('/profile', auth, profileCheck,  function(req , res) {
        res.render('profile.jade');
    });
    app.get('/logout' , function(req , res) {
        req.logout();
        res.json({
            'message': 'Bye'
        });
    });
}

控制器

app.controller('authController', ['$scope', '$http', '$window', 'authenticationService', 'restrictData', function($scope, $http, $window, authenticationService, restrictData) {
$scope.credentials = {
    name : "",
    email : "",
    password : ""
}
$scope.user = {};
$scope.regSubmit = function() {
    authenticationService.register($scope.credentials)
        .error(function(err) {
            console.log(err);
        }).then(function() {
            restrictData.getProfile()
                .success(function(data) {
                    $scope.user = data;
                }).error(function(e) {
                    console.log(e);
                });
            var url = '/profile';
            $window.location.href = url;
        });
}
$scope.logSubmit = function() {
    authenticationService.login($scope.credentials)
        .error(function(err) {
            console.log(err);
        }).then(function() {
            var url = '/profile';
            $window.location.href = url;
        });
}
$scope.isLoggedIn = authenticationService.isLoggedIn();
$scope.currentUser = authenticationService.currentUser();

}]);

服务1:

app.factory('authenticationService',['$http', '$window', '$timeout', '$q' , function($http, $window, $timeout, $q) {
var saveToken = function(token){
    $window.localStorage['mean-token'] = token;
}
var getToken = function(){
    return $window.localStorage['mean-token'];
}
var logout = function(){
    $window.localStorage.removeItem('mean-token');
}
var isLoggedIn = function() {
    var token = getToken();
    var payload;

    if(token) {
        payload = token.split('.')[1];
        payload = $window.atob(payload);
        payload = JSON.parse(payload);

        return payload.exp > Date.now() / 1000;
    } else {
        return false;
    }
}
var currentUser = function() {
    if(isLoggedIn()) {
        var token = getToken();
        var payload = token.split('.')[1];
        payload = $window.atob(payload);
        payload = JSON.parse(payload);
        return {
          email : payload.email,
          name : payload.name
        };
    }
}
register = function(user) {
  return $http.post('/api/register', user).success(function(data){
    saveToken(data.token);
  });
};

login = function(user) {
  return $http.post('/api/login', user).success(function(data) {
    saveToken(data.token);
  });
};
return {
    saveToken: saveToken,
    getToken: getToken,
    isLoggedIn: isLoggedIn,
    currentUser: currentUser,
    register: register,
    login: login,
    logout: logout
};

}]);

服务2:

app.factory('restrictData', function($http, authenticationService) {
var getProfile = function() {
    return $http.get('/profile', {
        headers: {
            Authorization: 'Bearer ' + authenticationService.getToken()
        }
    });
}
return {
    getProfile: getProfile
}

});

1 个答案:

答案 0 :(得分:0)

因此,根据我在研究中发现的情况,使用JWT保护非api路线是不明智或不可行的。因此,为了使我的应用程序正常工作,我将前端页面的所有路由转移到角度侧。它并不是特别想要,但它最终正在努力解决这个问题。

我删除了所有导致前端页面的get请求,如下所示:

app.get('/' , function(req , res) {
    res.sendFile(path.join(__dirname , '../public' , 'index.html'));
});

然后我使用routeProvider(确保在页面上包含angular-route以便这样做)来路由所有路径:

    app.config(function($routeProvider , $locationProvider) {
    $routeProvider
        .when('/', {
            templateUrl: './ui/home.html',
        }).when('/compare', {
            templateUrl: './ui/compare.html',
        }).when('/contact', {
            templateUrl: './ui/contact.html',
        }).when('/login', {
            templateUrl: './ui/login.html',
        }).when('/register', {
            templateUrl: './ui/register.html',
        }).when('/profile', {
            templateUrl: './ui/profile.html',
        });
    $locationProvider.html5Mode(true);
});
app.run(function($rootScope, $location, authenticationService) {
    $rootScope.$on('$routeChangeStart', function(event, nextRoute, currentRoute) {
      if ($location.path() === '/profile' && !authenticationService.isLoggedIn()) {
        $location.path('/');
      }
    });
});

然后相应地调整了其余的代码