Как избежать создания двойной сессии и гарантировать, что повар ie сохраняется в браузере, используя express -сессию и локальную стратегию паспорта? - PullRequest
0 голосов
/ 05 апреля 2020

В приложении узла / express я реализовал аутентификацию с использованием локальной стратегии паспорта и использовал express -сессию.

Используя почтальона, при нажатии localhost:3000/register, пользователь и документ сеанса создаются в базе данных, как и ожидалось.

Проблема заключается в том, когда я делаю то же самое из реагирующего приложения. Создаются два документа сеанса, и, хотя заголовок ответа имеет свойство setCook ie, в браузере не задается cook ie.

Вот мое приложение узла и мой компонент реакции.

// Node App
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const cors = require('cors');
const crypto = require('crypto');
const mongoose = require('mongoose');
const path = require('path');
const routes = require('./routes');

require('dotenv').config();

mongoose.set('useCreateIndex', true);

const connection = mongoose.createConnection(process.env.MONGODB_URI, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

const MongoStore = require('connect-mongo')(session);

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

/**
 * -------------- SESSION SETUP ----------------
 */

const sessionStore = new MongoStore({
  mongooseConnection: connection,
  collection: 'sessions',
});

const sessionOptions = {
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  store: sessionStore,
  cookie: {
    maxAge: 1000 * 60 * 60 * 24, // Equals 1 day (1 day * 24 hr/1 day * 60 min/1 hr * 60 sec/1 min * 1000 ms / 1 sec)
  },
};

app.use(session(sessionOptions));

/**
 * -------------- PASSPORT AUTHENTICATION ----------------
 */

function validPassword(password, hash, salt) {
    var hashVerify = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('hex');
    return hash === hashVerify;
}

/**
 * Local Strategy
 */
const localStrategyOptions = {
  usernameField: 'email',
  passwordField: 'password',
};

const localStrategyVerifyCallback = (username, password, done) => {
  User.findOne({ 'local.email': username })
    .then((user) => {
      if (!user) {
        return done(null, false);
      }

      const isValid = validPassword(password, user.local.hash, user.local.salt);
      if (isValid) {
        return done(null, user);
      } else {
        return done(null, false);
      }
    })
    .catch((err) => {
      done(err);
    });
};

passport.use(
  new LocalStrategy(localStrategyOptions, localStrategyVerifyCallback)
);

/**
 * Serializer and Deserializer
 */

passport.serializeUser((user, done) => {
  done(null, user.id);
});

passport.deserializeUser((userId, done) => {
  User.findById(userId)
    .then((user) => {
      done(null, user);
    })
    .catch((err) => done(err));
});

app.use(passport.initialize());
app.use(passport.session());


/**
 * CORS
 */

app.use(cors());

/**
 * -------------- ROUTES ----------------
 */

router.post('/register', (req, res, next) => {
  const saltHash = genPassword(req.body.password);
  const newUser = new User({
    local: {
      email: req.body.email,
      hash: saltHash.hash,
      salt: saltHash.salt,
      admin: true,
    },
    verification: {
      email: req.body.email,
    },
  });

  newUser
    .save()
    .then(user => {
      res.send({
        id: user._id,
        email: user.local.email,
      });
    })
    .catch(err => console.log('err: ', err));

});

app.use((req, res, next) => {
  const error = new Error('Not found');
  error.status = 404;
  next(error);
});

app.use((error, req, res, next) => {
  res.status(error.status || 500);
  res.json({
    error: {
      message: error.message,
    },
  });
});

/**
 * -------------- APP LISTEN ----------------
 */

app.listen(process.env.PORT, () => {
  console.log(`App is running on port ${process.env.PORT}`);
});

import React, { useContext, useState } from "react";
import { Segment, Form, Input, Button } from "semantic-ui-react";

export default function SignupLocalStrategy() {
  const email = useFormInput("");
  const password = useFormInput("");

  const onSubmit = () => {
    fetch(`http://localhost:3000/register`, {
      method: "post",
      headers: { "Content-Type": "application/json" },
      mode: "cors",
      body: JSON.stringify({
        email: email.value,
        password: password.value,
      }),
    })
      .then((res) => (res.ok ? res : Promise.reject(res)))
      .catch((err) => err);
  };

  return (
    <Segment basic>
      <Form onSubmit={onSubmit}>
        <Form.Group widths="3">
          <Form.Field width={6}>
            <Input placeholder="Enter Email" {...email} type="email" required />
          </Form.Field>
          <Form.Field width={6}>
            <Input
              placeholder="Enter Password"
              {...password}
              type="password"
              required
            />
          </Form.Field>
          <Form.Field width={4}>
            <Button fluid primary>
              New Contact
            </Button>
          </Form.Field>
        </Form.Group>
      </Form>
    </Segment>
  );
}

function useFormInput(initialValue) {
  const [value, setValue] = useState(initialValue);

  const handleChange = (e) => {
    setValue(e.target.value);
  };

  const handleReset = () => {
    setValue("");
  };

  return {
    value,
    onChange: handleChange,
    onReset: handleReset,
  };
}
...