最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

登录表单和受保护的路由无法正常工作;登录成功后受保护的路由未打开

网站源码admin38浏览0评论

登录表单和受保护的路由无法正常工作;登录成功后受保护的路由未打开

登录表单和受保护的路由无法正常工作;登录成功后受保护的路由未打开

所以我有一个登录表单,当我提交它时,它会将用户名和密码毫无问题地发送到服务器。服务器验证它们,并且它们被批准。

但是当服务器向客户端发送令牌时,路由似乎仍然受到保护。它被重定向大约 1/4 秒,然后返回到

/admin
路线。我希望它重定向到
/tickets
路线并留在
/tickets
路线。

我知道现在身份验证极易受到攻击,但我只是想暂时使用它来了解更多有关受保护路由和身份验证系统的信息。这是代码:

protected.jsx

import React, { useState } from "react";
import { Outlet, Navigate } from "react-router-dom";
//Create a protected route, that can only be accessed with admin credentials
//For the prototype this will do
function Protected() {
    const token = localStorage.getItem('token');
    console.log(localStorage.getItem('token'));
    //the /admin route is the route to the login form.
    return token ? <Outlet /> : <Navigate to='/admin' />;
}

export default Protected;

服务.jsx:

import React from "react";
import Home from "../Home";
import TicketingSystem from "./TicketingSystem";
import Login from "./Login";
import Protected from "./Protected";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
//Creates protected routes, that will only allow authorized users to access with authorized credentials.
//At this point it will be hard coded, securely into the server
function Service(props) {
    return (
      <Router>
        <Routes>
          <Route path='/admin' element={<Login />} />
          <Route path='/' element={<Home />} />
          <Route element={<Protected />}>
            <Route path='/tickets' element={<TicketingSystem />} />
          </Route>
        </Routes>
      </Router>
    );
  }
  
export default Service;

登录.jsx

import React, { useState } from "react";
import { Grid, Typography, TextField, Button } from "@mui/material";
import "./media/login.css";
function Login(props) {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const handleSubmit = async (event) => {
        event.preventDefault();

        const res = await fetch ('/login-request', {
            method: 'POST',
            headers: {'Content-Type' : 'application/json'},
            body: JSON.stringify({username, password})
        });
        if(res.ok) {
            const {token} = await res.json();
            localStorage.setItem('token', token);
            props.history.push('/tickets')
        }
    }
    return (
        <React.Fragment>
            <Grid container justifyContent='center' alignItems='center'>
                <div id='login-block'>
                    <Typography align='center'>
                        <h1 id='login-title'>Admin Login</h1>
                        <form onSubmit={handleSubmit}>
                            <Grid item xs={12}>
                                <TextField
                                    id='username'
                                    name='username'
                                    variant='standard'
                                    label='username'
                                    size='small'
                                />
                                <br />
                            </Grid>
                            <Grid item xs={12}>
                                <br />
                                <TextField
                                    id='password'
                                    type='password'
                                    name='password'
                                    variant='standard'
                                    label='password'
                                    size='small'
                                />
                                <br />
                            </Grid>
                            <Grid item xs={12}>
                                <br />
                                <Button id='submit-login-request' variant='contained' type='submit'>
                                    Login
                                </Button>
                            </Grid>
                        </form>
                        <p id='l1'>The unauthorized use of this route, is illegal.</p>
                    </Typography>
                </div>
            </Grid>
        </React.Fragment>
    );
}

export default Login;

server.js

app.post('/login-request', (req, res, next) => {
    /*  You need to update the token in the front end to true to access tickets,
        But this is insecure, make sure the password is hashed and sent securely
        make sure users cant find vulnerabilities in the login form.
    '
    

    */

    console.log('recieved login request', req.body.username, req.body.password);
    const {username, password} = req.body;
    if(username === "admin" && password === "password"){
        const token = jwt.sign({username}, 'test');
        res.cookie('jwt', token, { httpOnly: true });

        // Redirect the user to the /tickets route
        res.status(302).setHeader('Location', '/tickets').end();
    

    }else{
        res.status(401).json({message: "invalid credentials"});
    }
});

无论如何,一旦服务器发送响应并获得批准,它就会重定向并停留在

/tickets
路线上吗?

经过一些审查,我注意到

localStorage
项目没有被创建。我相信这与它有关,但我不知道为什么没有创建它们。

回答如下:

您正在设置 cookie,但没有将令牌作为 JSON 响应的一部分发送给客户端。所以这个

const {token} = await res.json()
如果不抛出错误将返回undined。并且尝试使用 JavaScript 发出的请求的标头进行重定向是行不通的。

如果您想将令牌存储在本地存储中,一个解决方案是更改您的后端,以便您以 JSON 格式发送令牌,如下所示。这应该适用于您的 React 代码的当前状态:

app.post("/login-request", (req, res, next) => {
  const { username, password } = req.body;
  if (username === "admin" && password === "password") {
    const token = jwt.sign({ username }, "test");
    res.status(200).json({ token: token });
  } else {
    return res.status(401).json({ message: "invalid credentials" });
  }
});

但是说你想使用cookies。在这种情况下,需要进行多项更改。在后端,像你已经做的那样设置 cookie 并发送 200 成功消息而不是重定向。

在 React 部分,您可以使用全局状态,如 Context API,存储有关用户登录的信息,您在

Login
页面中设置,并能够在
Protected
中访问。因为浏览器上的 JavaScript 无法访问
httpOnly
cookie。

发布评论

评论列表(0)

  1. 暂无评论