В этом блоге я подробно расскажу вам об аутентификации. Аутентификация в основном проверяет пользователя и позволяет ему использовать вашу платформу, верно?

Таким образом, эта аутентификация может выполняться разными способами в зависимости от того, насколько они безопасны. Существует шесть уровней аутентификации, каждый уровень имеет свой тип безопасности.

Теперь сначала я дам обзор всех этих типов аутентификации, а позже мы рассмотрим каждый из них.

  • Уровень 1 просто позволяет пользователю зарегистрироваться, указав имя пользователя и пароль, которые хранятся в базе данных MongoDB. Это нельзя использовать в производственной среде.
  • Уровень 2 шифрует пароль и сохраняет его в базе данных. Это делает пароль безопасным в случае взлома базы данных.
  • Уровень 3 — это хеширование пароля. зашифрованные пароли можно расшифровать, а хешированные пароли практически невозможно взломать.
  • Уровень 4 — это соление и хеширование пароля, соление играет жизненно важную роль, поскольку хэш будет одинаковым, если слова повторяются. соление решает эту проблему.
  • Уровень 5 использует паспорт js с файлами cookie и сессиями. Здесь данные будут сохраняться до тех пор, пока пользователь не выйдет из системы, по сути, пользователь может уйти с половиной работы, и веб-сайт будет хранить их до тех пор, пока он не выйдет из системы.
  • И, наконец, самый важный уровень 6 — это OAuth. Это упрощает весь процесс, позволяя пользователю входить в систему через любые другие организации, такие как Google, Facebook и т. д.

Чтобы пройти через каждый из них, нам нужен файл app.js с готовым базовым подключением к серверу. Также форма для ввода имени пользователя и пароля с кнопками входа и регистрации.

const express = require('express');
const ejs = require('ejs');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const app = express();


app.use(express.static( "public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));

app.get("/", (req,res) => {
    res.render("home");
});

app.get("/login", (req,res) => {
    res.render("login");
});

app.get("/register", (req,res) => {
    res.render("register");
});





app.listen(3000, () => {
    console.log("server is running");
    });

Здесь, в приведенном выше коде, вы можете видеть, что у нас есть разные зависимости и маршрутизация, готовые для отображения дома, входа в систему и регистрации. Теперь наше подключение к серверу готово, и мы можем начать манипулировать этим файлом для реализации другого процесса аутентификации.

Уровень 1: имя пользователя и пароль с использованием базы данных.

Это самый простой способ аутентификации, но он не использовался и совсем не безопасен. Здесь мы просто подключаем его к MongoDB и сохраняем имя пользователя и пароль.
Теперь вы можете видеть в коде два app.post. мы используем app.post для получения имени пользователя и пароля, далее с помощью newUser.save мы сохраняем его и используем другой app.post для входа в систему. используйте User.findOne, чтобы позволить пользователю войти на нашу страницу, проверив, зарегистрирован он уже или нет.

const express = require('express');
const ejs = require('ejs');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const app = express();

const MONGO_URI = 'mongodb+srv://mydatabase:test%[email protected]/mydatabase';

app.use(express.static("public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));

mongoose.connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => console.log('Database connected'))
  .catch(err => console.error(err));

const dataSchema = new mongoose.Schema({
  user: String,
  password: String,
});

const Data = mongoose.model('Data', dataSchema);

app.get("/", (req, res) => {
  res.render("home");
});

app.get("/login", (req, res) => {
  res.render("login");
});

app.get("/register", (req, res) => {
  res.render("register");
});

app.post('/register', (req, res) => {
  const username = req.body;

  const newUser = new Data({
    user: username,
    password: password,
  });

  newUser.save()
    .then(() => res.render("blogs"))
    .catch(err => {
      console.error(err);
      res.status(500).send("Internal Server Error");
    });
});

app.post("/login", (req, res) => {
  const { username, password } = req.body;

  Data.findOne({ user: username })
    .then(foundUser => {
      if (foundUser) {
        if (foundUser.password === password) {
          return res.render("blogs");
        } else {
          return res.status(401).send("Unauthorized");
        }
      } else {
        return res.status(404).send("Invalid username or password");
      }
    })
    .catch(error => {
      console.error(error);
      res.status(500).send("Internal Server Error");
    });
});

app.listen(3001, () => {
  console.log("server is running");
});

Уровень 2: Шифрование пароля.

Поскольку мы знаем, что аутентификация уровня 1 совсем не безопасна, теперь здесь мы шифруем пароли, чтобы даже после того, как хакеры проникнут в нашу базу данных, пароли были в безопасности. Для этого мы должны установить mongoose-encryption.

шаг 1: запустите команду «npm i mongoose-encryption» в терминале вашего проекта.
Также добавьте const mongooseEncryption = require(‘mongoose-encryption’)

шаг 2: добавьте плагин, как показано ниже.
Под нашей схемой создайте свою секретную фразу и зашифруйте ее. Вы можете сделать это, как указано ниже. Секретную фразу рекомендуется хранить в файле .dotenv, а не в app.js, чтобы она не была раскрыта при загрузке на Github.

const secret : "iAmBatmanBelieveMe";
userSchema.plugin(encrypt, {blog: blog, encryptedFields: ['password'] });

наконец, файл app.js должен выглядеть примерно так.

const express = require('express');
const ejs = require('ejs');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const encrypt= require('mongoose-encryption');
const app = express();

const MONGO_URI = '';


app.use(express.static( "public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));

mongoose.connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => console.log('Database connected'))
  .catch(err => console.log(err));

const dataSchema = new mongoose.Schema({
    user: String,
    password: String,
    
  });

const Data = mongoose.model('Data', dataSchema);
const secret : "iAmBatmanBelieveMe";
userSchema.plugin(encrypt, {blog: blog, encryptedFields: ['password'] });

//this particular get function routes to main website page, you are supposed leave it "/"

app.get("/", (req,res) => {
    res.render("home");
});

app.get("/login", (req,res) => {
    res.render("login");
});

app.get("/register", (req,res) => {
    res.render("register");
});

app.get("/blogs", (req,res) => {
    res.render("blogs");
});

app.post('/register', (req, res) => {
  const { username, password } = req.body;

  const newUser = new Data({
    user: username,
    password: password,
  });

  newUser.save()
    .then(() => res.render("blogs"))
    .catch(err => {
      console.error(err);
      res.status(500).send("Internal Server Error");
    });
});

app.post("/login", (req, res) => {
  const { username, password } = req.body;

  Data.findOne({ user: username })
    .then(foundUser => {
      if (foundUser) {
        if (foundUser.password === password) {
          return res.render("blogs");
        } else {
          return res.status(401).send("Unauthorized");
        }
      } else {
        return res.status(404).send("Invalid username or password");
      }
    })
    .catch(error => {
      console.error(error);
      res.status(500).send("Internal Server Error");
    });
});

app.listen(3001, () => {
    console.log("server is running");
    });

Уровень 3: Хэширование паролей

Хеширование паролей намного более безопасно, чем любое шифрование, потому что все, что зашифровано, может быть расшифровано, тогда как хеширование практически невозможно взломать.
Существуют различные алгоритмы хеширования, такие как md5, SHA-1, SHA-256, SHA-384, SHA-512. Здесь мы будем использовать алгоритм md5. Как обычно, первый шаг — установить пакет и потребовать его.
Чтобы начать работу, сначала нам нужно удалить пакет mongoose-encryption и плагин, который мы добавили в последнем методе. Теперь запустите npm i md5 в терминале каталога вашего проекта и добавьте const md5 = require(‘md5’)
Когда пользователь регистрируется, мы не хотим сохранять его пароли. Итак, мы меняем req.body.password, добавляя его в скобках md5. Что-то вроде этого.

app.post('/register', (req,res)=> {
   
    const newUser = new Data({
        user: req.body.username,
        password : md5(req.body.password)
        
});

то же самое нужно сделать для маршрута входа в систему, здесь также внесите те же изменения для пароля.

app.post('/login', (req,res)=> {
   const username = req.body.username; 
    const password = md5(req.body.password);
  Data.findOne(
.....
.....
....
        
});

Вот и все. с этими изменениями вы можете успешно использовать метод хеширования для защиты паролей, но есть одна проблема, если слова совпадают, хэш также будет таким же. я имею в виду, что если многие пользователи используют одни и те же общие повторяющиеся пароли, их можно идентифицировать на основе шаблонов. В прошлом было выпущено много повторяющихся паролей, и мы знаем для этого хэш.
Но для этого есть решение, мы используем то, что называется солением. мы увидим соление в следующем методе.

Окончательный код app.js для метода хеширования должен выглядеть так после внесения всех изменений, о которых говорилось ранее.

const express = require('express');
const ejs = require('ejs');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const md5 = require('md5');
const app = express();

const MONGO_URI = '';
const dataSchema = new mongoose.Schema({
    user: String,
    password: String,
    
  });

const Data = mongoose.model('Data', dataSchema);


app.use(express.static( "public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));

mongoose.connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => console.log('Database connected'))
  .catch(err => console.log(err));

//this particular get function routes to main website page, you are supposed leave it "/"

app.get("/", (req,res) => {
    res.render("home");
});

app.get("/login", (req,res) => {
    res.render("login");
});

app.get("/register", (req,res) => {
    res.render("register");
});

app.get("/blogs", (req,res) => {
    res.render("blogs");
});

app.post('/register', (req,res)=> {
   
    const newUser = new Data({
        user: req.body.username,
        password : md5('req.body.password')
        
});
newUser.save()
    .then(() => res.render("blogs"))
    .catch(err => {
      console.error(err);
      res.status(500).send("Internal Server Error");
    });
});


app.post("/login", (req,res) => {
    const username = req.body.username; 
    const password = md5('req.body.password');
    
   Data.findOne({ user: username })
    .then(foundUser => {
      if (foundUser) {
        if (foundUser.password === password) {
          return res.render("blogs");
        } else {
          return res.status(401).send("Unauthorized");
        }
      } else {
        return res.status(404).send("Invalid username or password");
      }
    })
    .catch(error => {
      console.error(error);
      res.status(500).send("Internal Server Error");
    });
});

app.listen(3001, () => {
    console.log("server is running");
    });

Уровень 4: Соление и перемешивание

Для выполнения этого процесса нам нужен пакет под названием bcrypt.
Используя этот пакет, мы также будем выполнять солевые раунды. Соленые раунды — это количество раз, когда вы сольете свой пароль. Больше раундов соления, больше затрат времени. В идеале провести 10–15 солевых раундов, чем мы здесь и займемся.
Во-первых, установите bcrypt и затребуйте его. А также определить количество раундов соли.

const bcrypt = require('bcrypt');
const saltRounds = 10;

Теперь измените почтовый маршрут регистрации следующим образом. Вы можете найти код bcrypt.hash в документации bcrypt npm. Эти строки кода выполняют раунды соли и создают хэш. Удалите весь код, связанный с md5, чтобы не было ошибок при запуске файла.

app.post('/register', (req,res)=> {
   bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
    const newUser = new Data({
        user: req.body.username,
        password : md5('req.body.password')
        
});
newUser.save()
    .then(() => res.render("secrets"))
    .catch(err => {
      console.error(err);
      res.status(500).send("Internal Server Error");
    });
}
});

Мы также должны изменить маршрут входа в систему с помощью bcrypt.compare, мы проверим, зарегистрирован ли пользователь, и его хэш хранится в базе данных. вы можете найти метод bcrypt.compare в документах bcrypt npm. Здесь мы заменили myPlaintextPassword на пароль, а хеш заменили на foundUser.password, поскольку хэш хранится внутри foundUser.

app.post("/login", async (req, res) => {
    const username = req.body.username; 
    const password = bcrypt('req.body.password');

    try {
        const foundUser = await User.findOne({ email: username });

        if (foundUser && (await bcrypt.compare(password, foundUser.password))) {
            res.render('blogs'); 
        } else {
            res.status(401).send("Invalid credentials");
    } catch (err) {
        console.error(err);
        res.status(500).send("Internal Server Error");
    }
});

Вот окончательный код app.js после внесения всех изменений.

const express = require('express');
const ejs = require('ejs');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const bcrypt= require('bcrypt');
const app = express();
const saltRounds = 10;

const MONGO_URI = '';
const dataSchema = new mongoose.Schema({
    user: String,
    password: String,
    
  });

const Data = mongoose.model('Data', dataSchema);

app.use(express.static( "public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));

mongoose.connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => console.log('Database connected'))
  .catch(err => console.log(err));

//this particular get function routes to main website page, you are supposed leave it "/"

app.get("/", (req,res) => {
    res.render("home");
});

app.get("/login", (req,res) => {
    res.render("login");
});

app.get("/register", (req,res) => {
    res.render("register");
});

app.get("/blogs", (req,res) => {
    res.render("blogs");
});

app.post('/register', (req,res)=> {
   bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
    const newUser = new Data({
        user: req.body.username,
        password : md5('req.body.password')
        
});
newUser.save()
    .then(() => res.render("secrets"))
    .catch(err => {
      console.error(err);
      res.status(500).send("Internal Server Error");
    });
}
});

app.post("/login", async (req, res) => {
    const username = req.body.username; 
    const password = bcrypt('req.body.password');

    try {
        const foundUser = await User.findOne({ email: username });

        if (foundUser && (await bcrypt.compare(password, foundUser.password))) {
            res.render('blogs'); 
        } else {
            res.status(401).send("Invalid credentials");
    } catch (err) {
        console.error(err);
        res.status(500).send("Internal Server Error");
    }
});

app.listen(3001, () => {
    console.log("server is running");
    });

Уровень 5: использование паспорта js

Теперь, как я уже упоминал о начале блога, здесь мы используем файлы cookie и сеанс. зачем нам это нужно? почему мы не можем просто использовать уровень 4 и не создавать файлы cookie. Это важно, потому что всякий раз, когда пользователь входит на платформу, он выполняет определенные действия и может оставить их наполовину. Таким образом, в основном создание файлов cookie позволяет пользователю сохранять их до тех пор, пока сеанс не завершится. Сеанс создается, когда пользователь входит в систему, и сеанс завершается, когда он выходит из системы.

Как всегда, первым делом устанавливаем пакеты, здесь нам понадобится куча пакетов.
npm i паспорт
npm i паспорт-локальный
npm i паспорт-локал-мангуст
npm i express -session
Как только мы добавим эти пакеты, они потребуются нам, как и раньше.

Теперь нам нужно вызвать сеанс, поэтому, как указано в документации по экспресс-сеансу, мы копируем этот код и редактируем его. Этот код должен быть размещен выше mongoose connect и ниже app.use и app.set. Далее мы скажем нашему приложению использовать паспорт для инициализации и запуска сеанса с использованием пакета паспорта. Все это показано ниже, обязательно ознакомьтесь с паспортными документами, чтобы узнать больше об этом.

app.use(session({
  secret: 'iAmBatmanBelieveMe',
  resave: false,
  saveUninitialized: true,

}));

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

Теперь мы добавим плагин, как вы помните, мы добавили плагин во время шифрования пароля. Здесь мы делаем что-то подобное, теперь мы настроим локальный мангуст в качестве плагина. Этот фрагмент кода должен быть написан после подключения Mongoose, убедитесь, что вы разместили его правильно.

userSchema.plugin(passportLocalMongoose);

Теперь нам нужно настроить локальный мангуст для паспорта, для этого мы должны вставить три строки кода из документации паспорта-локального-мангуста под моделью мангуста.

passport.use(User.createStrategy());

passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

Затем нам нужно настроить маршруты регистрации и входа в систему.
Чтобы сделать это, сначала очистите все, что мы написали в маршруте app.post, когда мы заглянем в документацию Passport-local-mongoose, они показали, как зарегистрировать любого пользователя в примерах. мы должны реализовать user.register и указать имя пользователя и пароль, тогда мы увидим, зарегистрирован ли пользователь уже или нет, и перенаправим его на нужную страницу.
Если аутентификация прошла успешно, мы пусть пользователи входят в раздел блогов. Если вы заметили, что раньше у нас никогда не было маршрута для блогов, потому что мы всегда позволяли им входить через маршрут входа или регистрации, но здесь мы используем password.authenticate, и пользователь будет в сеансе, пока не выйдет из системы, мы нужно создать отдельный маршрут для блогов. После того, как вы внедрите конфигурацию и маршрутизацию без каких-либо ошибок, вы можете заметить, что когда пользователь регистрируется в вашем проекте, будет создана сессия, это вы можете проверить в своем браузере.
Аналогичный процесс используется для маршрутизации входа в систему, здесь сначала мы должны создать пользователя позже, как указано в паспортных документах, мы будем использовать req.login, чтобы проверить, существует ли пользователь или нет, и перенаправить его на страницу блогов. мы используемpassport.authenticate, который помогает в проверке пользователя и создании сеанса.

//routing for blogs

app.get("/blogs", (req.res)=>{
if(req.isAuthenticated()){
  res.redirect("blogs");
}else{
  res.redirect("/login")
}
});


//paste this code in register route

app.post("/register", async (req, res) => {
  try {
    const user = await User.register({ username: req.body.username }, req.body.password);
    req.login(user, function (err) {
      if (err) {
        console.log(err);
        res.status(500).send("Internal Server Error");
      } else {
passport.authenticate("local")(req, res, function(){
        res.redirect("/blogs");
}
      }

    });
  } catch (err) {
    console.log(err);
    res.status(500).send("Internal Server Error");
  }
});



//paste this code inside login route


try {
  const user = new User({
    username: req.body.username,
    password: req.body.password,
  });

  await req.login(user);

  passport.authenticate("local")(req, res, function () {
    red.redirect("/blogs");
  });
} catch (err) {
  console.log(err);
}

Окончательный код app.js:

const express = require('express');
const ejs = require('ejs');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const passport = require(passport);
const passportLocal = require(passport-local);
const passportLocalMongoose = require(passport-local-mongoose);
const session= require(express-session);
const app = express();

const MONGO_URI = '';   



app.use(express.static( "public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));

app.use(session({
  secret: 'iAmBatmanBelieveMe',
  resave: false,
  saveUninitialized: true,

}));

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

mongoose.connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => console.log('Database connected'))
  .catch(err => console.log(err));
mongoose.set("useCreateIndex", true);

const dataSchema = new mongoose.Schema({
    user: String,
    password: String,
    
  });

userSchema.plugin(passportLocalMongoose);

const Data = mongoose.model('Data', dataSchema);
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

//this particular get function routes to main website page, you are supposed leave it "/"
app.get("/", (req,res) => {
    res.render("home");
});

app.get("/login", (req,res) => {
    res.render("login");
});

app.get("/register", (req,res) => {
    res.render("register");
});

app.get("/blogs", (req.res)=>{
if(req.isAuthenticated()){
  res.redirect("blogs");
}else{
  res.redirect("/login")
}
});

app.post("/register", async (req, res) => {
  try {
    const user = await User.register({ username: req.body.username }, req.body.password);
    req.login(user, function (err) {
      if (err) {
        console.log(err);
        res.status(500).send("Internal Server Error");
      } else {
passport.authenticate("local")(req, res, function(){
        res.redirect("/blogs");
}
      }

    });
  } catch (err) {
    console.log(err);
    res.status(500).send("Internal Server Error");
  }
});


app.post("/login",async(req,res) =>{
try {
  const user = new User({
    username: req.body.username,
    password: req.body.password,
  });

  await req.login(user);

  passport.authenticate("local")(req, res, function () {
    red.redirect("/blogs");
  });
} catch (err) {
  console.log(err);
}
)};

app.listen(3001, () => {
    console.log("server is running");
    });

Уровень 6: Oauth 2.0 — открытая авторизация

По сути, открытая авторизация — это способ позволить пользователю войти в систему без создания новой учетной записи. Он просто пройдет, используя свою учетную запись Google. Открытая авторизация не ограничивается только Google, вы можете сделать это с помощью Facebook, GitHub, LinkedIn и т. д. Но здесь мы будем идти через учетную запись Google. Для реализации этого очень важно посмотреть документы паспорта Google OAuth, там четко указано, что нам нужно зарегистрировать наш проект в облачной консоли google.
Итак, перейдите в консоль Google и создайте новый проект.

  • После создания нового проекта вам необходимо создать идентификатор клиента OAuth.
  • учетные данные › создайте идентификатор клиента OAuth
  • если вы работаете в локальной системе, добавьте URL-адрес локального хоста в источник javascript.
  • В разделе разрешенных URI перенаправления добавьте следующую ссылку, как показано ниже. здесь я использовал «блоги» в конце, потому что я хочу перенаправить на этот маршрут, выберите его в зависимости от ваших требований.

Как только вы закончите с настройкой идентификатора клиента. Добавьте пакет npm «passport-google-oauth20» в каталог вашего проекта. Кроме того, вставьте идентификатор клиента и секрет клиента в файл .env.
нам нужно добавить идентификатор клиента и секретные данные ниже сериализации и десериализации. Как вы заметили, делая паспорт js, мы создали сериализацию и десериализацию. Этот конкретный фрагмент кода, упомянутый ниже, написан в документах паспорта Google OAuth. Токен доступа позволяет нам получать данные, относящиеся к этому пользователю. Важно отметить, что findOrCreate — это не функция. поэтому мы должны установить пакет под названием mongoose findOrCreate. нам также нужно добавить плагин findOrCreate. Есть еще одна важная вещь, у нас есть только маршруты для входа и регистрации, но здесь мы делаем это напрямую через гугл-аккаунт. Итак, наш интерфейсный код для подключения к учетной записи Google не имеет app.get в серверной части для аутентификации, важно создать его. мы создаем еще одну функцию get для перенаправления на нужную страницу после аутентификации пользователя. Итак, в основном нам нужно создать два.
Весь дополнительный код, который нам нужно было добавить, показан ниже.

passport.use(new GoogleStrategy({
    clientID: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    callbackURL: "http://localhost:3000/auth/google/blogs",
    userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
}, async (accessToken, refreshToken, profile, cb) => {
  console.log(profile);
  
  try {
    const existingUser = await User.findOne({ googleId: profile.id });

    if (existingUser) {
      return cb(null, existingUser);
    } else {
      const newUser = new User({
        googleId: profile.id,
        email: profile.emails[0].value // Assuming the email is stored in the first element of the emails array
      });

      await newUser.save();
      return cb(null, newUser);
    }
  } catch (err) {
    return cb(err, null);
  }
}));

.
.
.

userSchema.plugin('findOrCreate');

.
.
.

app.get("/auth/google",
  passport.authenticate('google', { scope: ["profile"] })
);

app.get("/auth/google/blogs",
  passport.authenticate('google', { failureRedirect: "/login" }),
  function (req, res) {
    res.redirect("/blogs");
  }
);

окончательный файл app.js

require('dotenv').config();
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const session = require('express-session');
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const findOrCreate = require('mongoose-findorcreate');

const app = express();

const MONGO_URI = 'mongodb+srv://mydatabase:test%[email protected]/mydatabase';

app.use(express.static("public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));

app.use(session({
  secret: "Our little secret.",
  resave: false,
  saveUninitialized: false
}));

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

async function connectToDatabase() {
  try {
    await mongoose.connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
    console.log('Database connected');
  } catch (err) {
    console.error(err);
  }
}

connectToDatabase();

const userSchema = new mongoose.Schema({
  email: String,
  password: String,
  googleId: String,
  secret: String
});

userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);

const User = new mongoose.model("User", userSchema);

passport.use(User.createStrategy());
passport.serializeUser(function (user, done) {
  done(null, user.id); // Serialize only the user id
});
passport.deserializeUser(async function (id, done) {
  try {
    const user = await User.findById(id);
    done(null, user);
  } catch (err) {
    done(err, null);
  }
});


passport.use(new GoogleStrategy({
    clientID: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    callbackURL: "http://localhost:3000/auth/google/blogs",
    userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
}, async (accessToken, refreshToken, profile, cb) => {
  console.log(profile);
  
  try {
    const existingUser = await User.findOne({ googleId: profile.id });

    if (existingUser) {
      return cb(null, existingUser);
    } else {
      const newUser = new User({
        googleId: profile.id,
        email: profile.emails[0].value // Assuming the email is stored in the first element of the emails array
      });

      await newUser.save();
      return cb(null, newUser);
    }
  } catch (err) {
    return cb(err, null);
  }
}));



app.get("/", function (req, res) {
  res.render("home");
});

app.get("/auth/google",
  passport.authenticate('google', { scope: ["profile"] })
);

app.get("/auth/google/blogs",
  passport.authenticate('google', { failureRedirect: "/login" }),
  function (req, res) {
    res.redirect("/blogs");
  }
);

app.get("/login", function (req, res) {
  res.render("login");
});

app.get("/register", function (req, res) {
  res.render("register");
});

app.get("/blogs", async (req, res) => {
  try {
    const foundUsers = await User.find({ "blog": { $ne: null } });
    res.render("blogs", { usersWithBlogs: foundUsers });
  } catch (err) {
    console.log(err);
    res.status(500).send("Internal Server Error");
  }
});


app.post("/register", async (req, res) => {
  try {
    const user = await User.register({ username: req.body.username }, req.body.password);
    req.login(user, function (err) {
      if (err) {
        console.log(err);
        res.status(500).send("Internal Server Error");
      } else {
        res.redirect("/blogs");
      }
    });
  } catch (err) {
    console.log(err);
    res.status(500).send("Internal Server Error");
  }
});

app.post("/login", async (req, res) => {
  const user = new User({
    username: req.body.username,
    password: req.body.password
  });

  try {
    await req.login(user);
    res.redirect("/blogs");
  } catch (err) {
    console.log(err);
    res.status(500).send("Internal Server Error");
  }
});

app.listen(3000, function () {
  console.log("Server started on port 3000.");
});




Теперь у вас есть понимание аутентификации пользователей с помощью любого из этих методов, но добавление опции OAuth позволит пользователям легко входить в систему, чтобы им не нужно было тратить больше времени на создание учетной записи. Возиться с OAuth важно, так как это, в конечном счете, самое важное, что нужно знать.
Итак, в этом блоге все, следите за более разнообразным контентом.
Мир вам :)