头图

2023-07-18 更新

前后端分离项目建议还是使用token,也就是后端使用jsonwebtokenjwt进行token的生成和验证,token不存在本地,存在客户端,随请求头一起带来,安全性还是有保障

同时跨域问题建议还是后端进行解决,最好不要前端进行反向代理,容易出问题,由于我使用nodejs作为后端,解决跨域问题代码如下:

//安装cors库
npm i cors

//app.js 或者index.js文件引入
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors())

既然后端解决了跨域问题,那么前端这边就不需要进行反向代理了,即package.json中的proxy一行可以去掉了,然后记得把请求的地址也直接指向后端地址

注意,有个很重要的一点就是,如果后端也是在本地的话,前端一定不要把请求的后端的地址写成localhost

即下面这种写法
const url = 'http://localhost:xxxx
这种写法本地开发没有问题,但是打包后的前端发送请求如果是这个地址话就会404,所以还是修改为const url = 'http://127.0.0.1:xxxx'这样不论是开发环境还是生产环境都不会有请求错误的问题了


由于兴趣使然加薪的想法,由于本人是个菜鸡前端,想要学习后端,自然从自己最熟悉的语言javascript入手,所以开始学习nodejs,在b站上找到一个不错的学习视频
node学习
按照这个视频的进度。中后期的时候我已经可以利用node+express+mongoose+mongondb搭建后端服务器创造接口对数据进行增删改查了。
在利用session做登录验证的时候,遇到了第一个问题:
登录成功以后,session没有在浏览器中保存,后端的代码中无法通过请求头的session拿到预设的数据,导致一直处在未登录状态,同时数据库中,每一次登录都会增加一条session数据。
image.png

如下图,现在是登录成功的状态,并且按照代码,后端给响应头添加了session相关数据
image.png

但是后面跟着的请求,并没有携带这次的session,导致鉴权失败
image.png

首先看看对应的代码:

后端主要代码如下:

const mongoose = require('mongoose');
const express = require('express');
const cors = require('cors');
const indexRouter = require('./routes/index');
const session = require('express-session');
const MongoStore = require('connect-mongo');

const app = express();
app.use(session({
    name:'sid',//设置cookie的name
    secret: 'secret',//参与加密的字符串(签名)
    saveUninitialized: false,//是否每次请求都设置一个cookie用来存储session的id
    resave:true,//是否在每次请求的时候重新保存session
    store: MongoStore.create({
        mongoUrl:'mongodb://127.0.0.1:xxxx/数据库名'
    }),
    cookie:{
        httpOnly: true,//开启后前端无法通过js操作session
        maxAge:60*1000*5//过期时间
    }
}))

app.use(express.json());//获取请求体的中间件
app.use(cors())

首先是使用cors库进行跨域相关操作
然后使用express-session库进行session相关操作
使用connect-mongo库搭配express-session进行数据库的session写入操作

下面是具体的api的处理,登录请求来了以后,和数据库中的用户数据进行对比,如果存在并且密码正确,就在session中保存该次登录的usernameid

router.post('/login', (req, response) => {
    UserModel.findOne({ username: req.body.username }).then(res => {
        console.log('登录查询成功',res)
        if(res){
            if(res.password===req.body.password){
                req.session.username= res.username;
                req.session._id=res._id;
                response.json({
                    code:'0000',
                    msg:'登录成功',
                    data:res.username
                })
            }else{
                response.status(500).json({
                    code:'1001',
                    msg:'用户名或密码错误',
                    data:null
                })
            }
        }else{
            response.status(404).json({
                code:'1001',
                msg:'用户不存在',
                data:null
            })
        }
    }).catch(err=>{
        console.log('登录查询失败',err)
        response.status(500).json({
            code:'1001',
            msg:'登录失败',
            data:err
        })
    })
})

接下来就是book接口的代码了:

router.get('/book', (req, res) => {
    console.log('session',req.session)
    if(req.session.username){
        console.log('已登录')
        BooksModel.find().then((data) => {
            res.json({
                code: '0000',
                msg: '读取成功',
                data: data
            })
        }).catch(err => {
            res.status(500).json({
                code: '1001',
                msg: '数据读取失败',
                data: err
            })
        })
    }else{
        console.log('未登录')
        res.status(401).json({
            code:'1002',
            msg:'未登录',
            data:null
        })
    }
})

接口很简单,首先进行session的判断,如果session没有相关的用户信息,就判定为未登录。

按照这一套逻辑下来,只要登录成功了,session中就一定会有用户相关的信息,但是很遗憾,book的接口中,无论如何都没有用户相关的信息,而且请求头中也没有Cookie的相关值。

所以我就百度
react 不携带 session的解决办法
根据网上五花八门的回答折腾了很久,什么前端要在axios中设置axios.defaults.withCredentials= true; 什么后端要设置app.set('trust proxy', 1) 之类的,折腾了很久,这些

全部都没有用

本人亲测,全部都没有用


最后思来想去,灵光一闪,最终找到了问题所在

后端设置了允许跨域,前端这边直接请求后端,没有经过代理,导致每一个请求,都是无法追踪的请求,也就解释了为什么数据库中每一次登录成功,都会新增一条session数据,而不是覆盖。
但是前端为什么不能设置cookie我现在暂且蒙在鼓里。

知道了问题所在,那么就着手解决问题。

后端那边把关于跨域相关的代码去掉,即不在需要cors库相关的操作

前端这边在package.json文件中设置proxy,直接代理到后端的服务器的地址
image.png

同时请求中的url地址需要变为前端自己的地址,例如本地启动localhost:3000,那么地址就需要设置为http://localhost:3000/
image.png

这样就解决了明明登录以后,前端请求还是没有携带session相关信息的问题。


munergs
30 声望6 粉丝

现在即是最好。