【问题标题】:React profile page, how to avoid 'GET http://localhost:3001/users/profile 401 (Unauthorized)' when trying to get JSON data from back endReact 配置文件页面,如何在尝试从后端获取 JSON 数据时避免 \'GET http://localhost:3001/users/profile 401 (Unauthorized)\'
【发布时间】:2022-12-18 15:51:41
【问题描述】:

对于这个应用程序,我使用的是 React & Express。我在端口 3000 上运行 React,在端口 3001 上运行 Express。在 Express 端,我有使用 JWT 的身份验证工作。

首先,这是我的 auth.js 服务文件:

const jwt = require('jsonwebtoken');
const models = require('../models');
const bcrypt = require('bcryptjs');

var authService = {
    signUser: function (user) {
        const token = jwt.sign({
            Username: user.Username,
            UserId: user.UserId
        },
            'secretkey',
            {
                expiresIn: '1h'
            }
        );
        return token;
    },
    verifyUser: function (token) {
        try {
            let decoded = jwt.verify(token, 'secretkey');
            return models.users.findByPk(decoded.UserId);
        } catch (err) {
            console.log(err);
            return null;
        }
    },
    hashPassword: function (plainTextPassword) {
        let salt = bcrypt.genSaltSync(10);
        let hash = bcrypt.hashSync(plainTextPassword, salt);
        return hash;
    },
    comparePasswords: function (plainTextPassword, hashedPassword) {
        return bcrypt.compareSync(plainTextPassword, hashedPassword);
    }
}

module.exports = authService;

当用户向注册路由发出 POST 请求时,它会起作用:

router.post('/signup', function (req, res, next) {
  models.users.findOrCreate({
    where: {
      Username: req.body.username
    },
    defaults: {
      FirstName: req.body.firstName,
      LastName: req.body.lastName,
      Email: req.body.email,
      Password: authService.hashPassword(req.body.password)
    }
  })
    .spread(function (result, created) {
      if (created) {
        res.redirect("http://localhost:3000/login");
      } else {
        res.send('This user already exist')
      }
    });
});

注册适用于 Postman 和 React。

当用户向登录路由发出 POST 请求时,它会起作用:

router.post('/login', function (req, res, next) {
  models.users.findOne({
    where: {
      Username: req.body.username
    }
  }).then(user => {
    if (!user) {
      console.log('User not found')
      return res.status(401).json({
        message: "Login Failed"
      });
    } else {
      let passwordMatch = authService.comparePasswords(req.body.password, user.Password);
      if (passwordMatch) {
        let token = authService.signUser(user);
        res.cookie('jwt', token);
        res.redirect('http://localhost:3001/users/profile');
      } else {
        console.log('Wrong Password');
      }
    }
  });
});

登录适用于 Postman 和 React。

当用户向配置文件路由发出 GET 请求时,它会半工作:

router.get('/profile', function (req, res, next) {
  let token = req.cookies.jwt;
  if (token) {
    authService.verifyUser(token).then(user => {
      if (user) {
        res.setHeader('Content-Type', 'application/json');
        res.send(JSON.stringify(user));
      } else {
        res.status(401);
        res.send('Invalid authentication token');
      }
    });
  } else {
    res.status(401);
    res.send('Invalid authentication token');
  }
});

这仅适用于 Postman,我可以使用 Postman 查看我想要的数据。在 React 中,它不会获取我请求的配置文件路由。这是错误的来源:Console Error

在 React 端,这是配置文件 GET 组件:

import React from 'react';
import axios from 'axios';

class UserProfile extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            profileData: []
        }
    };

    fetchProfileData = () => {
        var encodedURI = window.encodeURI(this.props.uri);
        return axios.get(encodedURI).then(response => {
            this.setState(() => {
                return {
                    profileData: response.data
                };
            });
        });
    };

    componentDidMount() {
        this.fetchProfileData();
    }

    render() {
        console.log(this.state.profileData);
        if (this.state.profileData.length === 0) {
            return <div>Failed to fetch data from server</div>
        }

        const profile = this.state.profileData.map(user => (
            <div key={user.UserId}>Hello world</div>
        ));
        return <div>{profile}</div>
    }
}

export default UserProfile;

然后当我去渲染这个组件时,我只是:

<UserProfile uri="http://localhost:3001/users/profile" />

然后将呈现“无法从服务器获取数据”,然后控制台将记录“401(未经授权)”错误。我只是无法让它在 React 中呈现。

如果有人想要我的 Express app.js 文件以获取一些额外信息:

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var models = require('./models');
var cors = require('cors');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');

app.use(function (req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  next();
});

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(cors());

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  next(createError(404));
});

// error handler
app.use(function (err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

models.sequelize.sync().then(function () {
  console.log("DB Synced Up");
});

module.exports = app;

提前谢谢你。我一直在努力弄清楚这一点。

我试过玩弄我的 UserProfile 组件。我试过在 Express 中玩弄我的 /profile 路线。我得到的唯一 2 个错误是 401(未授权)和一些关于标题的错误。我知道我的 JWT 密钥被传递到反应端,因为当我执行“localhost:3000/profile”(反应端)时,我可以看到我存储了 cookie。我不确定如何在 React 端获得授权。在这一点上,我不知道该怎么做。这是我第一次尝试使用 React 设置身份验证。我一直使用 Express 和 .hbs 文件来呈现我的个人资料页面。但有人告诉我你不应该在后端呈现个人资料页面。所以,我在这里尝试用 React 来做。

我已经从后端渲染到前端,但没有使用 JWT。我坚信它与 JWT cookie 有关。我只是不知道如何在 React 中验证它。再次感谢。

【问题讨论】:

    标签: reactjs express authentication jwt


    【解决方案1】:

    我通过将其添加到我的 React 项目中来修复它:

    我将其添加到我的 fetchProfileData() 中

    { withCredentials: true }
    

        fetchProfileData = () => {
        var encodedURI = window.encodeURI(this.props.uri);
        return axios.get(encodedURI, { withCredentials: true }).then(response => {
            this.setState(() => {
                return {
                    profileData: response.data
                };
            });
        });
    };
    

    然后在 Express 中,我玩弄了我的 Profile 路线。将数据放入数组中,并按原样发送:

      router.get('/profile', function (req, res, next) {
        var userData = [];
        let token = req.cookies.jwt;
        if (token) {
          authService.verifyUser(token).then(user => {
            userData.push(user);
            res.send(userData);
          });
        } else {
          res.status(401);
          res.send('Invalid authentication token');
        }
     });
    

    【讨论】:

      猜你喜欢
      • 2021-12-31
      • 2020-10-20
      • 2018-09-27
      • 2017-12-20
      • 1970-01-01
      • 1970-01-01
      • 2013-07-06
      • 2021-04-27
      • 2021-06-02
      相关资源
      最近更新 更多