会话 ID 已检索,但会话在 nuxt 中未定义

问题描述 投票:0回答:2
  • 我有一个在端口 8000 上运行的快速后端,带有单个 /login 端点
  • 我有一个 nuxt 前端在端口 3000 上运行
  • 当我通过前端登录时,会话是在redis中创建的
  • 如果我刷新页面,会话未定义,但它能够检索会话 id

根据下面的屏幕截图,请注意控制台中会话 ID 是如何存在的,但会话未定义

我在这里只包含了 stackoverflow 上的相关文件,

express后端代码,

nuxt前端代码

我的app.js后端文件

require("dotenv-flow").config();
const cors = require("cors");
const http = require("http");
const express = require("express");
const passport = require("passport");
const connectRedis = require("connect-redis");
const Redis = require("ioredis");
const expressSession = require("express-session");
const { Strategy: LocalStrategy } = require("passport-local");
const { Server } = require("ws");

const RedisStore = connectRedis(expressSession);

const client = new Redis({
  host: process.env.REDIS_SESSION_HOST,
  port: process.env.REDIS_SESSION_PORT,
  password: process.env.REDIS_SESSION_PASSWORD,
  db: process.env.REDIS_SESSION_DB,
});

const loggedInUser = {
  userId: 1,
  userName: process.env.TEST_USER_EMAIL,
  isAdmin: false,
};

const sessionParser = expressSession({
  secret: process.env.SESSION_SECRET,
  resave: process.env.SESSION_RESAVE === "true",
  rolling: process.env.SESSION_ROLLING === "true",
  saveUninitialized: process.env.SESSION_SAVE_UNINITIALIZED === "true",
  cookie: {
    httpOnly: process.env.SESSION_HTTP_ONLY === "true",
    // Doesnt work if maxAge is not of type Number
    maxAge: +process.env.SESSION_MAX_AGE,
    // https://stackoverflow.com/questions/61999068/how-do-i-use-cookies-in-express-session-connect-sid-will-soon-be-rejected
    // https://github.com/jaredhanson/passport-twitter/issues/101
    sameSite: process.env.SESSION_SAME_SITE === "true",
    secure: process.env.SESSION_SECURE === "true",
  },
  store: new RedisStore({ client }),
});

const app = new express();

app.use(
  cors({
    origin: "http://localhost:3000",
    credentials: true,
  })
);

passport.serializeUser((user, done) => {
  done(null, user.userId);
});
passport.deserializeUser(async (userId, done) => {
  done(null, loggedInUser);
});

passport.use(
  "local",
  new LocalStrategy(
    {
      usernameField: "email",
      passwordField: "password",
      badRequestMessage: "email or password is missing",
    },
    async (email, password, done) => {
      if (
        email === process.env.TEST_USER_EMAIL &&
        password === process.env.TEST_USER_PASSWORD
      ) {
        return done(null, loggedInUser);
      } else {
        return done(null, false);
      }
    }
  )
);

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(sessionParser);
app.use(passport.initialize());
app.use(passport.session());
app.get("/user", (req, res) => {
  return res.json(req.user);
});
app.post("/login", (req, res, next) => {
  passport.authenticate("local", {}, async (error, user, info) => {
    if (error) {
      return next(error);
    }
    if (!user) {
      return res.json(false);
    }
    req.logIn(user, (error) => {
      if (error) {
        return next(error);
      }
      return res.json(user);
    });
  })(req, res, next);
});

app.post("/logout", (req, res, next) => {
  req.logout();
  req.session.destroy((err) => {
    if (err) {
      return next(err);
    }
    req.user = null;
    res.clearCookie("connect.sid");
    return res.json(true);
  });
});

const map = new Map();

const server = http.createServer(app);

const websocketServer = new Server({ noServer: true });

server.on("upgrade", (request, socket, head) => {
  sessionParser(request, {}, () => {
    console.log(
      request.session,
      request.user,
      request.session.user,
      request.headers.cookie
    );

    websocketServer.handleUpgrade(request, socket, head, function (ws) {
      websocketServer.emit("connection", ws, request);
    });
  });
});

websocketServer.on("connection", function (ws, request) {
  const user = request.session.user;

  map.set(user, ws);

  ws.on("message", function (message) {
    //
    // Here we can now use session parameters.
    //
    console.log(`Received message ${message} from user ${user}`);
  });

  ws.on("close", function () {
    map.delete(user);
  });
});

server.listen(+process.env.PORT, () => console.log(`server listening on ${process.env.PORT}`));

前端的 nuxt store/index.js 文件

export const state = () => ({
  redirect: null,
})

export const mutations = {
  SET_REDIRECT(state, redirect) {
    state.redirect = redirect
  },
}

export const actions = {
  nuxtServerInit({ commit, dispatch }, { $dayjs, req }) {
    console.log('req.user is', req.user);
    console.log('req.session is', req.session);
    console.log('req.headers are', req.headers);
    console.log('req.headers.cookie is ', req.headers.cookie);
    commit('me/SET_USER', req.user)
  },
}
express nuxt.js cross-domain session-cookies express-session
2个回答
0
投票

session cookie 和 session 的关联只存在于后端。这就足够了,因为前端仅充当后端的网关,它没有自己的功能(至少没有依赖于用户的功能)。

页面刷新后,后端仍然知道其会话中的用户,而前端不需要知道。换句话说:用户永远不会登录到前端,只能登录到后端。


0
投票

req.user 未定义的原因是因为 axios 默认情况下不发送凭证(严格来说 axios 模块)包括

  axios: {
    // Workaround to avoid enforcing hard-coded localhost:3000: https://github.com/nuxt-community/axios-module/issues/308
    baseURL: 'http://localhost:8000',
    credentials: true,
  },

here所述,它应该可以正常工作

© www.soinside.com 2019 - 2024. All rights reserved.