nodejs 和 Angular 应用程序使用 JWT 发送 401 Unauthorized 和 200 OK

Posted

技术标签:

【中文标题】nodejs 和 Angular 应用程序使用 JWT 发送 401 Unauthorized 和 200 OK【英文标题】:nodejs and angular app sending 401 Unauthorized and 200 OK with JWT 【发布时间】:2018-02-12 16:35:53 【问题描述】:

当我在我的表单上单击注册时,据我所知,角度是在节点服务器可以授权 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

);

【问题讨论】:

restrictData.getProfile() .success(function(data) $scope.user = data; ).error(function(e) console.log(e); ); var url = '/个人资料'; $window.location.href = 网址;为什么要触发 /profile 两次? @karthick 这是一个很好的观点。但是,当我删除 window.location 调用时,我应该如何将用户重定向到 /profile?返回 200 OK 但我留在 /register 页面。 profile.jade 未呈现,用户未重定向。 profile.jade 在 /profile 中渲染? @karthick 在响应中 app.get('/profile', auth, profileCheck, function(req , res) res.render('profile.jade'); );跨度> 【参考方案1】:

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

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

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('/');
      
    );
);

然后相应地调整其余代码

【讨论】:

以上是关于nodejs 和 Angular 应用程序使用 JWT 发送 401 Unauthorized 和 200 OK的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Mongoose、Express、Angular 4 和 NodeJS 上传/保存和显示图片

从 mongoDB 获取数据并使用 Angular 和 NodeJs 在屏幕上打印

nodejs 和 Angular 应用程序使用 JWT 发送 401 Unauthorized 和 200 OK

使用 nodejs/express 登录后将用户重定向到 Angular 应用程序

我可以在一个应用程序中使用 symfony nodeJS 和 angular [关闭]

如何使 SQLite 与 Angular 4+、Electron 和 NodeJS 一起工作