【问题标题】:Protected routes on React with JWT使用 JWT 在 React 上受保护的路由
【发布时间】:2021-03-17 06:21:13
【问题描述】:

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

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

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;

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

【问题讨论】:

    标签: javascript node.js reactjs jwt components


    【解决方案1】:

    大部分教程都使用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

    【讨论】:

      猜你喜欢
      • 2019-01-25
      • 2021-07-19
      • 2020-10-26
      • 2019-05-31
      • 1970-01-01
      • 2020-08-18
      • 2021-08-04
      • 2021-04-06
      • 2022-11-16
      相关资源
      最近更新 更多