javascript - 使用 JWT 在 React 上保护路由

标签 javascript node.js reactjs jwt components

我正在尝试为我的 React 项目创建 protected 路由,在后端我有 NodeJS。 我看了很多例子,他们使用 localStorage 或“fakeAuth”,所以我没有真正获得我需要的正确信息,我遇到的主要问题是,当我登录时,我应该如何保存我登录的信息ATM,以便我的前端部分可以看到。

在我的 PrivateRoute 组件中,我需要有描述我的统计信息的 bool 值(是否登录),但我真的不明白我应该如何从我的后端“提取”该信息 我的 PrivateRoute 组件:( bool 值应该代替 {{???????????????}} )

import React from "react";
import { Route, Redirect } from  "react-router-dom";
import {authentication} from "./login.component"
import axios from 'axios';
export const PrivateRoute = ({ component: Component, ...rest}) => (
    <Route 
        {...rest}
        render={props => 
            {{??????????????}} ? (
                <Component {...props} />
            ) : (
                <Redirect
                    to={{
                        pathname: "/login",
                        state: { from: props.location }
                    }}
                />  
            )
        }
    />
);

这是我的登录组件:

import React, { useState } from 'react';
import axios from 'axios';
const Login = () => {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const onChangeUsername = (e) => {
    setUsername(e.target.value);
    };
    const onChangePassword= (e) => {
     setPassword(e.target.value);
    };
    const onSubmit = async (e) => {
        const user = {
            username: username,
            password: password
            };
        e.preventDefault();
        await axios.post('http://localhost:5000/users/login', user);
    };
    return (
        <div className="Login">
           <h2>Traffic scan admin panel</h2>
           <div className="LoginInfo-Logins">
            <form>
                <input type="text"
                required
                className=""
                value={username}
                onChange={onChangeUsername}
                placeholder="Username*" 
                />
                <input type="text"
                required
                className=""
                value={password}
                onChange={onChangePassword}
                placeholder="Password*" 
                /> 
            </form>
           </div>
           <button onClick={onSubmit}>SIGN IN</button>
        </div>
    )
}
export default Login;

这是我的后端部分:

require('dotenv').config();

const router = require('express').Router();
const Users = require('../models/user.model');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');

router.route('/').get(authenticateToken, async (req, res) => {
    const user = await Users.findOne({username: req.body.username});
    if(!user) throw Error('User do not exist')
    res.json(user)
});

router.route('/add').post(async (req, res) => {
    try {
        const hashedPassword = await bcrypt.hash(req.body.password, 10); // 10 is const salt = await bcrypt.genSalt/*10 is default*/);
        const email = req.body.email;
        const username = req.body.username;
        const password = hashedPassword;
        const IP = req.connection.remoteAddress;
        const newUser = new Users({
            email,
            username,
            password,
            IP
        });
        newUser.save()
            .then(() => res.json('User added!'))
            .catch(err => res.status(400).json('Error: ' + err));
    } catch {
        res.status(500).send()
    }
});     
router.route('/login').post(async (req, res) => {
    const user = await Users.findOne({username: req.body.username});
    if(!user) throw Error('Password or Username')
    if(await bcrypt.compare(req.body.password, user.password)) {
        const accessToken = jwt.sign(user.toJSON(), process.env.ACCESS_TOKEN_SECRET, {expiresIn: 604800});
        res.json({ accessToken: accessToken });
    } else throw Error('Password or Username is incorrect');
    
});
function authenticateToken (req, res, next) {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1];
    if(token == null) return res.sendStatus(401);
    
    jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user)=>{
        if(err) return res.send(403);
        req.user = user;
        next();
    })
}
module.exports = router;

也许有人可以帮助我,关于如何做的任何建议、教程、示例都会有所帮助。

最佳答案

大多数教程都使用 localStoragecookie,因为您希望即使在用户刷新页面后也能保留登录状态,这样他们就不必每次都要重新登录。但要回答您的问题,您可以这样做:

import React, { useState } from "react";
import { Route, Redirect, BrowserRouter } from "react-router-dom";
import "./style.css";
import axios from "axios";

function yourLoginPostApi() {
  return new Promise(r => setTimeout(() => r(true), 1000));
}

function Login({ onSuccess }) {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  let [loading, setLoading] = useState(false);
  const onChangeUsername = e => {
    setUsername(e.target.value);
  };
  const onChangePassword = e => {
    setPassword(e.target.value);
  };
  const onSubmit = async e => {
    const user = {
      username: username,
      password: password
    };
    e.preventDefault();
    setLoading(true);
    // Uncomment this line and remove the next one since it's a fake api call
    // let response = await axios.post("http://localhost:5000/users/login", user);
    let response = await yourLoginPostApi();
    setLoading(false);
    onSuccess(response);
  };
  return (
    <div className="Login">
      <h2>Traffic scan admin panel</h2>
      <div className="LoginInfo-Logins">
        <form>
          <input
            type="text"
            required
            className=""
            value={username}
            onChange={onChangeUsername}
            placeholder="Username*"
          />
          <input
            type="text"
            required
            className=""
            value={password}
            onChange={onChangePassword}
            placeholder="Password*"
          />
        </form>
      </div>
      <button onClick={onSubmit}>SIGN IN</button>
      <div>{loading && "Please wait..."}</div>
    </div>
  );
}

function PrivateRoute({ children }) {
  let [loggedIn, setLoggedIn] = useState(false);
  return loggedIn ? (
    <div>
      {children}
      <button onClick={() => setLoggedIn(false)}>log out</button>
    </div>
  ) : (
    <Login onSuccess={() => setLoggedIn(true)} />
  );
}

export default function App() {
  return (
    <BrowserRouter>
      <PrivateRoute>
        <div>Stuff only a logged in user should see</div>
      </PrivateRoute>
    </BrowserRouter>
  );
}

你可以看到 demo on stackblitz

关于javascript - 使用 JWT 在 React 上保护路由,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65156405/

相关文章:

javascript - 使用nodejs异步回调处理循环

javascript - Promise 返回数据 '<pending>'

audio - React-sound 在移动设备上不起作用

reactjs - 在另一个 axios 请求中使用 axios 响应数据

javascript - 预先输入 Bloodhound 排序返回值。

javascript - 使用 Javascript 或 jQuery 警告 iframe 内的隐藏文本

javascript - 使用 If 条件不返回函数中的值

node.js - Ubuntu 哪里可以看到 console.logs

javascript - 通过模块增强扩展 Material UI 主题无法正常工作

javascript - 如何使用 resharper testr jasmin 测试 spa js 模块?