【问题标题】:How to use protected api routes and verify JWT tokens with Nodejs?如何使用受保护的 api 路由并使用 Nodejs 验证 JWT 令牌?
【发布时间】:2019-11-22 08:15:12
【问题描述】:

我正在尝试实现一个注册和登录系统,目前我能够在数据库中注册和存储数据并登录,因为我已经测试过它,我使用console.log(token); 来查看我是否是一个令牌.然而,在登录后,我进入了我的网页(React 组件)/Profile,它获取了一个 GET users/current,但我在控制台中收到了这个。

GET /users/current 401 2.083 ms - 33

也在我的浏览器控制台中

 Uncaught (in promise) SyntaxError: Unexpected token A in JSON at position 0

我觉得令牌没有正确传递,我是使用 JWT 的新手,所以任何帮助都很有用。

服务器.js

var express = require('express');
var cors = require('cors');
var bodyParser = require('body-parser');
var app = express();
var port = process.env.PORT || 5000;
var morgan = require('morgan');
const auth = require('./middleware/auth');
const User = require('./models/User');

app.use(bodyParser.json());
app.use(cors());
app.use(
  bodyParser.urlencoded({
    extended: false
  })
);

// use morgan to log requests to the console
app.use(morgan('dev'));

var Users = require('./routes/Users');

app.use('/users', Users);

// Create a Server
const PORT = process.env.PORT || 5000; // Environment variable or port 5000

app.listen(PORT, () => console.log(`Server started on port ${PORT}`));

用户.js

const express = require('express');
const users = express.Router();
const cors = require('cors');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const bodyParser = require('body-parser');
const User = require('../models/User');
const config = require('config');
const auth = require('../middleware/auth');


users.use(
  bodyParser.urlencoded({
    extended: true
  })
);

users.use(bodyParser.json());

users.use(cors());

users.post('/register', (req, res) => {
  const today = new Date();
  const userData = {
    first_name: req.body.first_name,
    last_name: req.body.last_name,
    email: req.body.email,
    password: req.body.password,
    created: today
  };

  User.findOne({
    where: {
      email: req.body.email
    }
  })
    //TODO bcrypt
    //Need validation to appear on console and in view
    .then(user => {
      if (!user) {
        bcrypt.hash(req.body.password, 10, (err, hash) => {
          userData.password = hash;
          User.create(userData)
            .then(user => {
              res.json({ status: user.email + 'Registered!' });
            })
            .catch(err => {
              res.send('error: ' + err);
            });
        });
      } else {
        res.json({ error: 'User already exists' });
      }
    })
    .catch(err => {
      res.send('error: ' + err);
    });
});

users.post('/authenticate', (req, res) => {
  User.findOne({
    where: {
      email: req.body.email
    }
  }).then(user => {
    if (user) {
      if (bcrypt.compareSync(req.body.password, user.password)) {
        const payload = {
          check: true
        };

        const token = jwt.sign(payload, config.get('myprivatekey'), {
          expiresIn: 1440 // expires in 24 hours
        });

        res.json({
          message: 'authentication done ',
          token: token
        });
        console.log('Successful Login');
        console.log(user.first_name);
      } else {
        res.json({ message: 'please check your password !' });
        console.log('incorrect password');
      }
    } else {
      res.json({ message: 'user not found !' });
      console.log('user cannot be found');
    }
  });
});

users.get('/current', auth, async (req, res) => {
  const user = await User.findById(req.user._id).select('-password');
  console.log(user);
  res.send(user);
});

Auth.js

const jwt = require('jsonwebtoken');
const config = require('config');

module.exports = function(req, res, next) {
  //get the token from the header if present
  const token = req.headers['x-access-token'] || req.headers['authorization'];
  //if no token found, return response (without going to the next middelware)
  if (!token) return res.status(401).send('Access denied. No token provided.');

  try {
    //if can verify the token, set req.user and pass to next middleware
    const decoded = jwt.verify(token, config.get('myprivatekey'));
    req.user = decoded;
    next();
  } catch (ex) {
    //if invalid token
    res.status(400).send('Invalid token.');
  }
};

/Profile 网页(React 组件)

import React, { Component } from 'react';
import jwt_decode from 'jwt-decode';
import axios from 'axios';

class Profile extends Component {
  constructor() {
    super();
    this.state = {
      first_name: '',
      last_name: '',
      email: '',
      errors: {}
    };
  }

  componentDidMount() {
    fetch('http://localhost:5000/users/current')
      .then(function(response) {
        return response.json();
      })
      .then(function(myJson) {
        console.log(JSON.stringify(myJson));
      });
  }

  render() {
    return (
      <div className='container'>
        <div className='jumbotron mt-5'>
          <div className='col-sm-8 mx-auto'>
            <h1 className='text-center'>PROFILE</h1>
          </div>
          <table className='table col-md-6 mx-auto'>
            <tbody>
              <tr>
                <td>First Name</td>
                <td>{this.state.first_name}</td>
              </tr>
              <tr>
                <td>Last Name</td>
                <td>{this.state.last_name}</td>
              </tr>
              <tr>
                <td>Email</td>
                <td>{this.state.email}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    );
  }
}

export default Profile;

【问题讨论】:

  • Offtopic:请记住,jwt 可以被暴力破解,当这种情况发生时,攻击者可以创建自己的 jwt 并对其进行签名..
  • @RaymondNijland 你有什么建议?
  • 而不是使用 JWT 登录。会话更好吗?
  • 研究一些算法容易出现的问题
  • 代码的哪一行出现语法错误?

标签: node.js reactjs jwt


【解决方案1】:

您应该只在 server.js 中使用 cors 和 bodyparser 的代码。无需在 User.js 中使用它。使用 express-jwt 进行 JWT 身份验证。

var jwt = require('express-jwt');

users.get('/current', jwt({secret: config.get('myprivatekey')}), async (req, res) => {
  const user = await User.findById(req.user._id).select('-password');
  console.log(user);
  res.send(user);
});

请参考https://www.npmjs.com/package/express-jwt

同时在标头中发送令牌以进行获取

fetch('http://localhost:5000/users/current', {
    method: 'GET',
    mode: 'cors',
    headers: {
        'Authorization': 'Bearer xxxxx.yyyyy.zzzzz',
    },
})

请将xxxxx.yyyyy.zzzzz 替换为 JWT 令牌。

【讨论】:

  • 谢谢,我会试试这个。什么应该进入 x , y 和 z 。对不起,我是使用 JWT 的新手
  • 欢迎。当您使用 localhost:5000/users/authenticate 进行身份验证时,您将获得令牌。您应该将该令牌存储在 localStorage 中,并在您访问受保护的 API 时将其发送到标头中。 JWT 包含三个部分。我提到了 xxxxx.yyyyy.zzzzz 作为占位符。详情请参考https://jwt.io/introduction/
  • 标题仍有问题。不确定授权后要包括什么:“轴承 x.y.z”。另外我如何将它存储为本地存储,以便在获取之前执行此操作? const token = localStorage.getItem('token');
  • 我知道它需要标头、有效负载和签名,但你如何检索它
  • 根据您的代码,成功验证后会返回一个令牌。您应该将此令牌存储在 localStorage 中。有关 localStorage 的详细信息,请参阅https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage。可以检索令牌并将其与 fetch const token = localStorage.getItem('token'); fetch('http://localhost:5000/users/current', { method: 'GET', mode: 'cors', headers: { 'Authorization': 'Bearer '+token, }, }) 的标头一起传递
猜你喜欢
  • 2020-11-18
  • 1970-01-01
  • 2016-01-21
  • 2014-10-18
  • 2021-03-10
  • 2019-09-14
  • 1970-01-01
  • 2020-08-21
  • 1970-01-01
相关资源
最近更新 更多