【问题标题】:JWT must be provided - Delete method returning token as null instead of user token必须提供 JWT - Delete 方法将令牌返回为 null 而不是用户令牌
【发布时间】:2022-01-27 19:35:31
【问题描述】:

正如标题所说,我有问题。我将向您展示 NodeJS 中的代码。请求是 blogRouter.delete

controllers/blog.js(仅删除方法)

    const blogsRouter = require('express').Router()
    const jwt = require('jsonwebtoken');
    const Blog = require('../models/blog')
    const User = require('../models/user')

    blogsRouter.delete('/:id', async (request, response, next) => {

      const token = getTokenFrom(request)
      console.log('token: ',token)

      try {
        const decodedToken = jwt.verify(token, process.env.SECRET)

        if (!token || !decodedToken.id) {
          return response.status(401).json({ error: 'token missing or invalid' })
        }
        const userid = await User.findById(decodedToken.id)
        const blogs = await Blog.findById(request.params.id)

        if(blogs.user.toString() === userid.toString()) {
          await Blog.findByIdAndRemove(request.params.id)
          response.status(204).end()
        } else {
          response.status(404).end()
        }
      }catch(exception){next(exception)}  
    })

当我控制台日志令牌时,我通过辅助函数 getTokenFrom 得到 null

getTokenFrom

const getTokenFrom = request => {
  const authorization = request.get('authorization')
  if (authorization && authorization.toLowerCase().startsWith('bearer ')) {
    return authorization.substring(7)
  }
  return null
}

在发布请求令牌中工作得很好。我能够创建一个博客。但是当我用删除方法做同样的事情时,它不会显示令牌。它说它的 null。所以它正确地返回了我的 getTokenFrom 函数,但我希望能够在 delete 方法中访问令牌,这样我就可以删除某些博客。

控制器/登录

const jwt = require('jsonwebtoken')
const bcrypt = require('bcryptjs')
const loginRouter = require('express').Router()
const User = require('../models/user')


loginRouter.post('/', async (request, response) => {
    const body = request.body

    const user = await User.findOne({username: body.username})
    const passwordCorrect = user == null ? 
    false : await bcrypt.compare(body.password, user.passwordHash)

    if(!(user && passwordCorrect)) {
        return response.status(401).json({
            error: "Invalid username or passowrd"
        })
    }

    const userForToken = {
        username: user.username,
        id: user._id,
    }

    const token = jwt.sign(userForToken, process.env.SECRET)

    response.status(200).send({token, username: user.username, name: user.name})
})

module.exports = loginRouter

https://prnt.sc/qfjgka --> 这是一张图片。我发送 http.delete 请求,我得到令牌 null。必须提供 JWT。我不知道是我的错。我尝试了很多东西,但它不会工作。 我试图用 token.request.jwt 定义令牌,但后来​​我得到它未定义。

我只需要在 blogRoute.delete 方法中以某种方式访问​​该令牌。

感谢转发

编辑:这是我的 post 方法,当我在此处控制台日志令牌时,它会返回令牌的值,但是当我在 delete 方法中执行相同操作时,它将不起作用

blogsRouter.post('/', async (request, response, next) => {

  const body = request.body
  console.log('body', body)
  const token = getTokenFrom(request)
  console.log('token: ', token)

  try {
    const decodedToken = jwt.verify(token, process.env.SECRET)
    if (!token || !decodedToken.id) {
      return response.status(401).json({ error: 'token missing or invalid' })
    }

  const user = await User.findById(decodedToken.id)


  const blog = new Blog({
    title: body.title,
    author: body.author,
    url: body.url,
    likes: body.likes,
    user: user._id
  })


    const savedBlog = await blog.save()
    user.blogs = user.blogs.concat(savedBlog._id)
    await user.save()
    response.json(savedBlog.toJSON())
  } catch(exception) {
    next(exception)
  }
})

【问题讨论】:

  • 您是否在 DELETE 请求的标头中包含 JWT 令牌?鉴于令牌作为登录请求的一部分作为正文的一部分而不是 cookie 传递,这将需要手动完成。
  • 我通过这个函数包含它 const getTokenFrom = request => { const authorization = request.get('authorization') if (authorization && authorization.toLowerCase().startsWith('bearer')) { return authorization.substring(7) } return null }
  • 但它返回 null 而不是 token
  • 在删除请求中,您发送的令牌是否与在发布请求中相同?您可以在删除请求中显示请求标头吗?
  • 如何显示请求头?

标签: node.js express jwt http-delete


【解决方案1】:

在您记录请求标头的屏幕截图中,似乎没有授权标头,因此您遇到了错误。如果能成功发送授权头,问题就解决了。

顺便说一句,在每条路由中检查令牌并验证它并不是一个好的解决方案。

您最好使用身份验证中间件进行令牌验证。

1-) 像这样创建一个身份验证中间件:

中间件\auth.js

const jwt = require("jsonwebtoken");

module.exports = function(req, res, next) {

  let token;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith('Bearer')
  ) {
    token = req.headers.authorization.split(' ')[1];
  } 

  if (!token) {
     return res.status(401).json({ error: 'token missing' })
  }

  try {
    const decoded = jwt.verify(token, process.env.SECRET);
    req.user = decoded;
    next();
  } catch (ex) {
    return res.status(400).json({ error: 'token invalid' })
  }
};

2-) 在需要身份验证的任何地方使用此身份验证中间件。现在我们的路线更干净、更短了。

const blogsRouter = require("express").Router();
const jwt = require("jsonwebtoken");
const Blog = require("../models/blog");
const User = require("../models/user");
const auth = require("../middleware/auth");

blogsRouter.delete("/:id", auth, async (request, response, next) => {
  try {

    const userid = request.user.id;    //we set the user in the auth middleware, so we can access it like this
    const blogs = await Blog.findById(request.params.id);

    if (blogs.user.toString() === userid.toString()) {
      await Blog.findByIdAndRemove(request.params.id);
      response.status(204).end();
    } else {
      response.status(404).end();
    }
  } catch (exception) {
    next(exception);
  }
});

blogsRouter.post("/", auth, async (request, response, next) => {
  try {
    const body = request.body
    const user = await User.findById(request.user.id);

    const blog = new Blog({
      title: body.title,
      author: body.author,
      url: body.url,
      likes: body.likes,
      user: user._id
    });

    const savedBlog = await blog.save();
    user.blogs = user.blogs.concat(savedBlog._id);
    await user.save();
    response.json(savedBlog.toJSON());
  } catch (exception) {
    next(exception);
  }
});

通过这种方式,您可以在授权标头中以Bearer TOKEN..... 的形式发送您的令牌

【讨论】:

  • 请稍后再试。
  • @VeljkoKukic 我希望你喜欢这个重构,这是我们检查身份验证的方式。如果您以正确的格式(Bearer ....)在授权标头中发送令牌,它必须有效。
  • 我想知道为什么这个答案在没有任何评论的情况下被否决。就可能出现的问题提出更好的解决方案是不是很糟糕?
  • 我没有反对它../。我稍后会检查它,看看你的解决方案是否有效。我会批准它:)
  • @VeljkoKukic 我没有对你说:) 有人做到了,但没有发表任何评论:)
【解决方案2】:

" if (blogs.user.toString() === userid.toString()) {" 限制用户访问他自己的资源很重要,因此路由类似于: 删除帖子/:id 而不是删除 /users/:uid/posts/:id ,因为黑客将能够猜出 id 并删除其他人的帖子。

【讨论】:

    猜你喜欢
    • 2021-01-22
    • 2018-06-11
    • 2020-05-25
    • 1970-01-01
    • 2020-06-01
    • 2017-03-27
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    相关资源
    最近更新 更多