Passport-local: Izinkan paspor untuk mengembalikan pesan kegagalan otentikasi melalui variabel

Dibuat pada 13 Mar 2012  ·  25Komentar  ·  Sumber: jaredhanson/passport-local

Sesuai diskusi saya dengan Jared melalui IM, masalah ini membutuhkan kemampuan untuk mengirimkan kembali pesan kegagalan otentikasi ke fungsi passport.authenticate. Mungkin melalui:

passport.authenticate(... func(err, pengguna, info))

Masalahnya sekarang adalah tidak ada cara yang baik untuk mengembalikan pesan kesalahan dari LocalStrategy. Satu-satunya pilihan adalah mengembalikan kegagalan server melalui 'err' yang akan menyebabkan server hanya mengembalikan kesalahan 500 HTTP, atau menggunakan solusi yang menggunakan objek pengguna untuk mengembalikan pesan kesalahan.

Akibatnya, fungsi yang sudah selesai mungkin akan terlihat lebih seperti ini:

selesai (null, false, 'password buruk')

Ini adalah jsfiddle tempat saya mengalami masalah ini. Dalam contoh ini, server hanya mengembalikan kesalahan 500 untuk semua kegagalan -- dan saya ingin mengembalikan string kesalahan sebagai gantinya:

http://jsfiddle.net/nd8LZ/1/

Komentar yang paling membantu

@nickjj Saya setuju sepenuhnya dengan semua poin Anda. Argumen yang harus diselesaikan dalam panggilan balik verifikasi dibawa melalui panggilan balik autentikasi khusus, jadi ketika Anda memanggil done() :

done(null, false, { message: 'bad password' })

Argumen terakhir itu adalah argumen info ke panggilan balik autentikasi:

app.get('/login', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) { return next(err) }
    if (!user) {
      // *** Display message without using flash option
      // re-render the login form with a message
      return res.render('login', { message: info.message })
    }
    req.logIn(user, function(err) {
      if (err) { return next(err); }
      return res.redirect('/users/' + user.username);
    });
  })(req, res, next);
});

Dari sana Anda dapat memanggil pesan apa pun yang Anda inginkan berdasarkan permintaan ( render dalam kasus ini), dan menggunakan detail apa pun yang disediakan di info .

Saya sendiri bukan penggemar terbesar flash, dan saya sadar bahwa itu tidak digunakan lagi di Express. (Saya kira Anda akan melihat middleware untuk polyfill kembali, meskipun.) Yang mengatakan, jika Anda tidak pernah menggunakan opsi, itu tidak akan mempengaruhi Anda. Saya tidak ingin membuat kerangka kerja Paspor agnostik, dan opsi ini sebenarnya hanyalah jalan pintas untuk pola umum, Express atau lainnya. Pesan flash cukup umum sehingga masuk akal untuk disertakan.

Saya terbuka untuk menambahkan opsi tambahan jika ada cara yang lebih baik untuk mengirim pesan atau operasi standar lainnya. Di luar itu, panggilan balik khusus adalah cara yang harus dilakukan.

Apakah itu tampak baik bagi Anda?

Semua 25 komentar

Itu pada dasarnya bagaimana saya melakukannya juga, kecuali saya tidak mengembalikan json. Selama fungsi baru memungkinkan Anda untuk mengembalikan variabel apa pun dan bukan hanya string dan Anda dapat meneruskan variabel itu ke res.xxx() di router Anda (sehingga Anda dapat meneruskan kesalahan autentikasi apa pun ke tampilan Anda dengan mudah) saya akan senang .

Sunting:
Jared, saya membaca beberapa masalah terkait dan Anda menyebutkan mem-flash pesan secara default. Apakah Anda berbicara tentang menggunakan express' req.flash()? Saya akan menjauh dari itu karena sudah usang di express 3.0:
https://github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x (periksa bagian yang dihapus)

paspor-lokal v0.1.2 mengatasi masalah ini. Lihat komentar ini pada edisi Paspor #12 untuk detailnya.

Perhatikan juga bahwa sintaks di atas akan berfungsi

done(null, false, 'bad password')

tetapi bentuk yang disukai adalah menggunakan hash opsi

done(null, false, { message: 'bad password' })

karena lebih dapat dikembangkan untuk penggunaan di masa mendatang.

Bisakah Anda mengubah cara pesan dikembalikan? Menggunakan req.flash() itu konyol. Mungkin Anda bisa membuatnya melakukan kesalahan dan membiarkan pengembang memutuskan bagaimana menanganinya?

@nickjj Saya setuju sepenuhnya dengan semua poin Anda. Argumen yang harus diselesaikan dalam panggilan balik verifikasi dibawa melalui panggilan balik autentikasi khusus, jadi ketika Anda memanggil done() :

done(null, false, { message: 'bad password' })

Argumen terakhir itu adalah argumen info ke panggilan balik autentikasi:

app.get('/login', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) { return next(err) }
    if (!user) {
      // *** Display message without using flash option
      // re-render the login form with a message
      return res.render('login', { message: info.message })
    }
    req.logIn(user, function(err) {
      if (err) { return next(err); }
      return res.redirect('/users/' + user.username);
    });
  })(req, res, next);
});

Dari sana Anda dapat memanggil pesan apa pun yang Anda inginkan berdasarkan permintaan ( render dalam kasus ini), dan menggunakan detail apa pun yang disediakan di info .

Saya sendiri bukan penggemar terbesar flash, dan saya sadar bahwa itu tidak digunakan lagi di Express. (Saya kira Anda akan melihat middleware untuk polyfill kembali, meskipun.) Yang mengatakan, jika Anda tidak pernah menggunakan opsi, itu tidak akan mempengaruhi Anda. Saya tidak ingin membuat kerangka kerja Paspor agnostik, dan opsi ini sebenarnya hanyalah jalan pintas untuk pola umum, Express atau lainnya. Pesan flash cukup umum sehingga masuk akal untuk disertakan.

Saya terbuka untuk menambahkan opsi tambahan jika ada cara yang lebih baik untuk mengirim pesan atau operasi standar lainnya. Di luar itu, panggilan balik khusus adalah cara yang harus dilakukan.

Apakah itu tampak baik bagi Anda?

Di 3.x, express sekarang memiliki middleware khusus tampilan tempat Anda dapat menyuntikkan variabel lebar situs ke semua tampilan Anda dengan app.locals.use(...).

Alur kerja untuk menggunakannya (misalnya) adalah:

Di app.js...

app.locals.use(function(req, res) {
   // Expose "error" and "message" to all views that are rendered.
   res.locals.error = req.session.error || '';
   res.locals.message = req.session.message || '';

   // Remove them so they're not displayed on subsequent renders.
   delete req.session.error;
   delete req.session.message;
});

sumber: https://github.com/visionmedia/express/blob/master/examples/blog/app.js#L32

Di salah satu rute Anda, Anda hanya perlu melakukan req.session.message = info.message dengan pengaturan baru tetapi rute tidak memiliki akses ke info. Apakah Anda mengatakan bahwa kami masih perlu menggunakan panggilan balik khusus untuk menampilkan pesan dengan cara yang tidak bergantung pada req.flash()?

Saya masih cukup baru di node/express/JS secara umum, maaf jika pertanyaan saya terbelakang.

Pertanyaan Anda bagus. Anda memiliki pegangan yang baik tentang apa yang sedang terjadi.

Apakah Anda mengatakan bahwa kami masih perlu menggunakan panggilan balik khusus untuk menampilkan pesan dengan cara yang tidak bergantung pada req.flash()?

Jika Anda menggunakan Express 3, ya, untuk saat ini. Begini cara kerjanya:

app.get('/login', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) { return next(err) }
    if (!user) {
      // *** Display message using Express 3 locals
      req.session.message = info.message;
      return res.redirect('login');
    }
    req.logIn(user, function(err) {
      if (err) { return next(err); }
      return res.redirect('/users/' + user.username);
    });
  })(req, res, next);
});

Sekarang, saya akui itu adalah upaya ekstra yang cukup untuk membuat pesan sederhana. Inilah filosofi saya tentang ini:

Paspor dirancang untuk menjadi middleware otentikasi generik, dapat digunakan dalam kerangka kerja aplikasi apa pun. Ini dilakukan dengan mendelegasikan kontrol kembali ke aplikasi untuk tugas-tugas yang secara logis berada di bawah tanggung jawab aplikasi. Rendering, redirecting, messaging, dll semua termasuk dalam kategori itu, jadi setiap pekerjaan kustom yang unik untuk aplikasi Anda atau kerangka dasar aplikasi Anda harus ditangani di callback.

Di mana pola umum muncul di seluruh kerangka kerja, Passport akan memberikan opsi untuk membuat pola tersebut lebih mudah (dengan demikian keberadaan failRedirect, failFlash, dll.) Pesan flash adalah salah satu pola umum tersebut, jadi sangat berguna jika Passport mendukungnya.

Saya pribadi mendukung keputusan @visionmedia untuk menghapus req.flash() dari Express. Saya pikir keputusan itu akan menghasilkan fungsionalitas yang diadopsi oleh middleware tingkat rendah yang dapat dimasukkan dan digunakan kembali di seluruh kerangka kerja. (Saya sedang mengerjakan middleware seperti itu saat ini; saya akan memperbarui di sini ketika diterbitkan).

Jika pola perpesanan berbeda muncul yang berguna di berbagai aplikasi, maka saya akan mempertimbangkan untuk menambahkan opsi bawaan ke Paspor (misalnya failureMessage atau semacamnya). Tetapi sampai saat itu, panggilan balik khusus memungkinkan Anda untuk mencapai apa pun yang dibutuhkan aplikasi Anda.

Oke terima kasih. Itu menjelaskan hampir semuanya. Saya tidak sabar untuk tetap menggunakan Paspor.

@nickjj Saya baru saja menerbitkan connect-flash, yang merupakan middleware yang dapat Anda
https://github.com/jaredhanson/connect-flash

Jika Anda menggunakannya, Anda juga dapat menggunakan opsi successFlash dan failureFlash dengan passport.authenticate() .

Saya juga anti req.flash(), jadi kemungkinan besar saya tidak akan menggunakannya, namun saya pikir banyak orang akan menikmatinya dengan beberapa kali saya melihat req.flash() dalam contoh express aplikasi. Di samping catatan middleware connect-flash Anda adalah contoh yang sangat bagus/dasar tentang cara mengimplementasikan middleware "nyata" dengan benar di express.

Setiap kali auth gagal selalu mengatakan "Kredensial yang hilang" yang tampaknya dikodekan ke dalam lib paspor itu sendiri.

Ketika saya menimpanya dengan mengikuti contoh panggilan balik khusus dan menampilkan info.message, ia selalu melaporkan "Kredensial yang hilang", seperti mengabaikan apa pun yang ada di passport.use(LocalStrategy...).

Saya juga sepertinya selalu "gagal melakukan deserialize pengguna di luar sesi" setiap kali saya berhasil masuk. Saya telah mengikuti contoh dan tutorial Anda. Saya sudah mencoba menggunakan toko sesi ekspres standar dan redis. Halaman yang sedang saya kerjakan berfungsi sebelum saya memutakhirkan paspor/paspor-lokal ke versi terbaru. Tahu apa yang terjadi? Haruskah saya memposting semua kode?

@nickjj Sudahkah Anda mengetahui penyebab masalah Anda?

Semuanya bekerja dengan baik untuk saya, dan jika Paspor rusak secara keseluruhan, saya akan mendengarnya dari orang lain. Karena saya tidak, saya kira itu adalah sesuatu yang spesifik untuk pengaturan Anda. Posting Intisari dengan kode yang mereproduksi masalah, dan beri tahu saya jika saya dapat memberikan bantuan.

Ya, saya menggunakan versi express 3.x yang memiliki versi buggy connect (saya pikir itu 2.0.0 atau 2.0.1). Tj memperbaiki bug dalam koneksi baru-baru ini yang melakukan sesuatu untuk memperbaiki sesi. Setelah memutakhirkan ke paspor koneksi terbaru kembali berfungsi.

Saya baru saja mem-porting aplikasi contoh Anda di repo paspor-lokal Anda ke aplikasi 3.x ekspres dan itu berfungsi. Ini bekerja menggunakan penyimpanan sesi koneksi standar dan penyimpanan sesi redis (modul koneksi-redis).

Masalah lain yang saya miliki adalah kesalahan saya. Ketika saya mengubah data tiruan Anda untuk mengakses database nyata (mongodb), itu mengalami masalah deserializing data karena saya meneruskan id dari deserializeUser() langsung ke mongo findOne() saya sebagai string tetapi perlu dikonversi ke ObjectID terlebih dahulu.

Saya masih belum 100% nyaman dengan tumpukan baru ini jadi ketika saya membaca panduan tutorial Anda dan mengikutinya, itu menunjukkan Anda menggunakan findOne() selama deserializeUser(). Saya baru saja berpikir "oh ok, dia menggunakan findOne() jadi dia pasti menggunakan mongo juga dan hanya melewati id tanpa masalah".

Semuanya tampaknya baik-baik saja sekarang untuk menggunakan paspor-lokal.

Masalah sebenarnya sekarang adalah, jika saya menggunakan panggilan balik khusus untuk mendapatkan pesan khusus dengan express 3.x dan saya harus menentukan strategi lokal saya sendiri tergantung pada apa yang memeriksa data, lalu mengapa saya menggunakan paspor-lokal?

Mengapa tidak menggunakan fungsi standar untuk mengautentikasi terhadap basis data saya dan menulis lebih sedikit kode di rute saya untuk mendeteksi apakah itu upaya masuk yang baik atau buruk?

Saya pasti ingin menggunakan paspor-xxx jika saya memutuskan untuk mendukung masuk dengan layanan pihak ke-3, tetapi saya tidak yakin mengapa lokal (dengan panggilan balik khusus) bahkan layak digunakan? Bisakah Anda menjual saya untuk menggunakannya?

Satu-satunya cara yang baik untuk menempatkan pesan kegagalan yang saya temukan adalah dengan cara ini.

app.post("/login", passport.authenticate("local", 
  { successRedirect: "/", 
    failureRedirect: "/login", 
    failureMessage: "Invalid username or password" }));

Kemudian pesan akan disimpan di req.session.messages, yang merupakan array, satu-satunya masalah adalah statis dan saya pikir ada bug bahwa array akan menggabungkan pesan yang sama berulang-ulang. Ini diperbaiki dengan kode berikut, setelah respons diberikan: P

res.render("login", { login_errors: req.session.messages || [] });
req.session.messages = [];

Apa gunanya menggunakan failureFlash sini? Cara bagaimana menunjukkan kesalahan bervariasi dari kasus ke kasus, dan mengapa kita tidak bisa menggunakan fungsi panggilan balik untuk mengatasinya apa pun yang masuk akal?
Kutipan dari dok:

Menyetel opsi failFlash ke true menginstruksikan Passport untuk mem-flash pesan kesalahan menggunakan pesan yang diberikan oleh panggilan balik verifikasi strategi

  • pertama-tama, saya tidak ingin mem-flash pesan kesalahan
  • kedua, sepertinya paspor bahkan tidak dapat mem-flash pesan tanpa menginstal ketergantungan lain? dan saya kira saya mungkin hanya menginstalnya untuk mem-flash satu pesan kesalahan login.

Bagaimana saya bisa mengembalikan banyak pesan, misalnya jika login gagal saya ingin mengembalikan pesan kesalahan yang sesuai dan email yang dimasukkan sehingga saya dapat memberi makan input email lagi.

done(null, false, { message: 'bad password', email: emailVariable});

Ini tidak bekerja.

@silps

req.session.messages = [];

Apa yang harus dilakukan ini? Menyetel ulang pesan sesi? Saya tidak berpikir ini akan berhasil.

Saya hanya menampilkan pesan terakhir dalam array. Seperti di EJS:

<% if (login_errors.length > 0) { %> <%= login_errors[login_errors.length -1]%><br> <% }%>

`

@GEOLYTIX ya, pendekatan ini akan berfungsi juga, hanya saja setiap kali saya me-refresh situs ada satu lagi pesan yang sama dalam array, jadi saya membersihkannya setiap kali, tetapi cara Anda juga berfungsi

@jaredhanson Saya memiliki situasi pemrograman di mana saya ingin tahu apakah pengguna ada, karena saya akan mengambil tindakan aplikasi yang berbeda berdasarkan apakah mereka sudah ada atau tidak. Jadi saya berharap akan ada URL passport.js untuk memberikan dukungan untuk /exist , di mana saya memberikan nama pengguna dan paspor mengembalikan 0 atau 1. Ok, ini tidak tersedia. Jadi saya memposting ke /login dengan nama pengguna dan kata sandi. Kata sandinya bisa apa saja. Dalam fungsi passport.use jika nama pengguna tidak ditemukan, saya kembali-

    if (!user) {
        return done(null, false, { "rtnCode": 1 });    // user not found, user does not exist
    }

Jika pengguna ditemukan, saya malah mengembalikan with- done(null, false, { "rtnCode": 2 })

                  // check if password is valid     
                   if (!validatePassword(password, passHash)) {
                        //return done(null, false);                         // as per passport.js example
                        return done(null, false, { "rtnCode": 2 });
                   }

Sekarang, di passport.authenticate('local-login', function(err, user, info)
info akan berisi { "rtnCode": 1 } atau { "rtnCode": 2 }

Artinya di

        // incorrect Username or password
        if (!user) {
                //return res.redirect('/auth/login');     // as per passport.js example
            return res.json(info);               // rtn code- { "rtnCode": 1 } or { "rtnCode": 2 }
                                                                                 // user does not exist, or does exist
            }

Sekarang saya dapat mengirim kode pengembalian tertentu ke aplikasi saya yang memberi saya informasi bahwa pengguna itu ada atau tidak. Inilah masalahnya. Meskipun aliran eksekusi berakhir dengan pengembalian dan tidak pernah berjalan-
req.logIn(user, function(err)

Jika sekarang saya mengeluarkan ajax GET dengan nama pengguna yang saya tahu ada dan kata sandi palsu, saya masuk, saya bisa membaca database.

Itu sangat tidak terduga karena saya tidak pernah mengeluarkan req.logIn(). Dan tentu saja ini adalah masalah keamanan. Intinya di sini adalah bahwa pada nama pengguna atau kata sandi "buruk" di /login saya, saya tidak ingin pergi ke halaman web, saya ingin mengambil tindakan yang berbeda dalam kode.

```

Saya menggunakan angular4 dengan paspor, apakah saya bisa mendapatkan res tanpa fitur redirect di paspor?

Jadi kebetulan paspor memiliki fungsi untuk menyelesaikannya dalam dokumentasi mereka,
Panggilan balik panggilan bagian khusus membantu saya menyelesaikannya

//contoh rute
router.get('/', function (req, res, next) { res.render('administrator/login', { title: 'Login Admin', alerts: req.flash() }); });

//penangan ejs
`<% if (alerts.error) { %>
<% alerts.error.forEach(function(msg) { %>

<% }); %>
<% } %>
<% jika (peringatan.berhasil) { %>
<% alerts.success.forEach(function(msg) { %>

<% }); %>
<% } %>`

terima kasih @jaredhanson !! kamu menyelamatkanku hhhh

Ada banyak kebingungan di web mengenai bagaimana informasi diteruskan sebagai info ke panggilan balik verifikasi digunakan, misalnya di sini . Masalah utama yang membingungkan orang adalah bahwa yang berikut ini tidak berfungsi:

const express = require('express');
const app = express();
const passport = require('passport');
const { Strategy: LocalStrategy } = require('passport-local');

app.use(express.json());

passport.use(new LocalStrategy({ failWithError: true },
    (username, password, cb) => {
        console.log(`executing local strategy ${username} and ${password}`);
        // user expects 'message: `user not found`' to be forwarded to the 
        // client along with the 401 Unauthorized response
        cb(null, false, { message: `user not found` });
    })
);

app.post('/login', passport.authenticate('local', { session: false }))

app.listen(3000, () => {
  console.log(`Run:`);
  console.log(`curl -v --header "Content-Type: application/json" -d '{"username":"dauser","password":"dapass"}' -X POST http://localhost:3000/login`);
});

Dengan kata lain, tindakan default middleware paspor-lokal adalah mengabaikan apa yang diteruskan ke verify(null, false, info) di slot info , kecuali jika pengguna memanggil fungsi middleware yang dihasilkan oleh passport.authenticate() langsung melalui passport.authenticate(...)(req, res, next) dan mengirimkan tanggapannya sendiri. @jaredhanson komentar dari 2012 tampaknya menunjukkan bahwa ini adalah perilaku yang diinginkan, setidaknya pada 2012.

Ini membingungkan pengguna yang berharap untuk menggunakan passport.authenticate() sebagai middleware sebelum penangan permintaan mereka sendiri.

Yang memperburuk masalah adalah fakta bahwa passport.authenticate mengambil beberapa opsi , tidak ada yang memiliki perilaku yang diinginkan untuk menyampaikan informasi kepada klien.

Saya bertanya-tanya apakah ini bisa/harus direvisi. Tampaknya, bagi saya, pola yang dibuat dengan sempurna untuk - secara default - mengambil objek yang diteruskan sebagai info dan mengirimkannya sebagai badan JSON ke klien sebagai tanggapan. Jika tidak secara default, opsi sendErrorInfoToClient dapat disediakan. Atau apakah saya salah, dan praktik terbaik untuk tidak mengirim apa pun dengan 401?

Sudah 7 tahun dan saya rasa fitur ini tidak akan pernah diterapkan. Yang mengatakan, Anda dapat membuat solusi untuk menjaga strategi sebagai fungsi middleware dan masih memiliki pesan khusus yang dikirim kembali ke klien (dan fungsi tersebut dapat dibuat dapat digunakan kembali untuk pengontrol lain jika diinginkan):

Rute ekspres:

const { login } = require("../controllers/login)";
const localLogin = require("../services/strategies)";

module.exports = app => {
  app.post("/api/login", localLogin, login);
};

Paspor Middleware

const bcrypt = require("bcryptjs");
const passport = require("passport");

// reusable func to return errors to client
const sendError = (err, res) => res.status(400).json({ err: err.toString() });

const badCredentials = "There was a problem with your login credentials. Please make sure your username and password are correct.";

passport.use(
  "local-login",
  new LocalStrategy(
    {
      usernameField: "email",
      passwordField: "password",
      passReqToCallback: true,
    },
    async (req, email, password, done) => {
      try {
        // check to see if the user already exists
        const existingUser = await User.findOne({ email });
        if (!existingUser) return done(badCredentials, false);

        // compare password to existingUser password
        const validPassword = await bcrypt.compare(
          password,
          existingUser.password,
        );
        if (!validPassword) return done(badCredentials, false);

        return done(null, existingUser);
      } catch (err) {
        return done(err, false);
      }
    },
  ),
);

// exporting a wrapper function that will invoke the passport.authenticate method
module.exports = (req, res, next) => {
  const { email, password } = req.body;

  // if email or password are missing, send an error back to the client
  if (!email || !password) return sendError(badCredentials, res);

  passport.authenticate("local-login", (err, user) => {
    // if an error was returned by the strategy, send it to the client
    if (err) return sendError(err, res);

    // manually setting the logged in user to req.user 
    // optionally, you can set it to "req.session" if you're using some sort of session
    req.user = user;

   // invoking "next" to continue to the controller
    next();
  })(req, res, next);
};

// alternatively, you can use a promise as well...
module.exports = async (req, res, next) => {
  const { email, password } = req.body;

  if (!email || !password) return sendError(badCredentials, res);

  try {
    const user = await new Promise((resovle, reject) => {
      passport.authenticate("local-login", (err, user) =>
        err ? reject(err) : resolve(user),
      )(req, res, next);
    });

    req.user = user;
    next();
  } catch (err) {
    return sendError(err, res);
  }
}

Pengontrol Ekspres

exports.login = (req, res, done) => {
  // do any additional aggregation with "req.user"

  res.status(202).json({ ...req.user, ...etc });
};

Keuntungan terbesar dari pendekatan ini adalah Anda sekarang dapat menguji unit strategi autentikasi secara terpisah dari pengontrol. Kerugiannya adalah ini masih tidak mendukung sesi paspor (yang tampaknya tidak didukung saat menggunakan panggilan balik khusus apa pun).

Sudah 7 tahun dan saya rasa fitur ini tidak akan pernah diterapkan. Yang mengatakan, Anda dapat membuat solusi untuk menjaga strategi sebagai fungsi middleware dan masih memiliki pesan khusus yang dikirim kembali ke klien (dan fungsi tersebut dapat dibuat dapat digunakan kembali untuk pengontrol lain jika diinginkan):

Rute ekspres:

const { login } = require("../controllers/login)";
const localLogin = require("../services/strategies)";

module.exports = app => {
  app.post("/api/login", localLogin, login);
};

Paspor Middleware

const bcrypt = require("bcryptjs");
const passport = require("passport");

// reusable func to return errors to client
const sendError = (err, res) => res.status(400).json({ err: err.toString() });

const badCredentials = "There was a problem with your login credentials. Please make sure your username and password are correct.";

passport.use(
  "local-login",
  new LocalStrategy(
    {
      usernameField: "email",
      passwordField: "password",
      passReqToCallback: true,
    },
    async (req, email, password, done) => {
      try {
        // check to see if the user already exists
        const existingUser = await User.findOne({ email });
        if (!existingUser) return done(badCredentials, false);

        // compare password to existingUser password
        const validPassword = await bcrypt.compare(
          password,
          existingUser.password,
        );
        if (!validPassword) return done(badCredentials, false);

        return done(null, existingUser);
      } catch (err) {
        return done(err, false);
      }
    },
  ),
);

// exporting a wrapper function that will invoke the passport.authenticate method
module.exports = (req, res, next) => {
  const { email, password } = req.body;

  // if email or password are missing, send an error back to the client
  if (!email || !password) return sendError(badCredentials, res);

  passport.authenticate("local-login", (err, user) => {
    // if an error was returned by the strategy, send it to the client
    if (err) return sendError(err, res);

    // manually setting the logged in user to req.user 
    // optionally, you can set it to "req.session" if you're using some sort of session
    req.user = user;

   // invoking "next" to continue to the controller
    next();
  })(req, res, next);
};

// alternatively, you can use a promise as well...
module.exports = async (req, res, next) => {
  const { email, password } = req.body;

  if (!email || !password) return sendError(badCredentials, res);

  try {
    const user = await new Promise((resovle, reject) => {
      passport.authenticate("local-login", (err, user) =>
        err ? reject(err) : resolve(user),
      )(req, res, next);
    });

    req.user = user;
    next();
  } catch (err) {
    return sendError(err, res);
  }
}

Pengontrol Ekspres

exports.login = (req, res, done) => {
  // do any additional aggregation with "req.user"

  res.status(202).json({ ...req.user, ...etc });
};

Keuntungan terbesar dari pendekatan ini adalah Anda sekarang dapat menguji unit strategi autentikasi secara terpisah dari pengontrol. Kerugiannya adalah ini masih tidak mendukung sesi paspor (yang tampaknya tidak didukung saat menggunakan panggilan balik khusus apa pun).

Terima kasih, ini sangat berguna dan bersih.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

jacargentina picture jacargentina  ·  7Komentar

matiasfha picture matiasfha  ·  15Komentar

jcyh0120 picture jcyh0120  ·  3Komentar

ghost picture ghost  ·  3Komentar

JonathanSum picture JonathanSum  ·  11Komentar
bleepcoder.com menggunakan informasi GitHub berlisensi publik untuk menyediakan solusi bagi pengembang di seluruh dunia untuk masalah mereka. Kami tidak berafiliasi dengan GitHub, Inc. atau dengan pengembang mana pun yang menggunakan GitHub untuk proyek mereka. Kami tidak meng-host video atau gambar apa pun di server kami. Semua hak milik masing-masing pemiliknya.
Sumber untuk halaman ini: Sumber

Bahasa pemrograman populer
Lebih banyak proyek GitHub

© 2024 bleepcoder.com - Contact
Made with in the Dominican Republic.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.