Zrozumienie serializacji paszportu bez postaci szeregowej

337

Jak wyjaśniłbyś laikowi przepływ pracy serializacji i deserializacji metod Passport.

  1. Dokąd się user.idudaje passport.serializeUser?

  2. Dzwonimy passport.deserializeUserzaraz po tym, gdzie pasuje do przepływu pracy?

    // used to serialize the user for the session
    passport.serializeUser(function(user, done) {
        done(null, user.id); 
       // where is this user.id going? Are we supposed to access this anywhere?
    });
    
    // used to deserialize the user
    passport.deserializeUser(function(id, done) {
        User.findById(id, function(err, user) {
            done(err, user);
        });
    });

Wciąż próbuję owinąć wokół niego głowę. Mam kompletną działającą aplikację i nie mam żadnych błędów.

Chciałem tylko zrozumieć, co się tutaj właściwie dzieje?

Każda pomoc jest mile widziana.

Anubhav
źródło

Odpowiedzi:

452
  1. Dokąd się user.idudaje passport.serializeUser?

Identyfikator użytkownika (podany jako drugi argument donefunkcji) jest zapisywany w sesji, a następnie wykorzystywany do pobierania całego obiektu za pomocą deserializeUserfunkcji.

serializeUserokreśla, które dane obiektu użytkownika powinny być przechowywane w sesji. Wynik metody serializeUser jest dołączany do sesji jako req.session.passport.user = {}. Tutaj na przykład byłoby (ponieważ podajemy identyfikator użytkownika jako klucz)req.session.passport.user = {id: 'xyz'}

  1. Dzwonimy passport.deserializeUserzaraz po tym, gdzie pasuje do przepływu pracy?

Pierwszy argument parametru deserializeUserodpowiada kluczowi obiektu użytkownika, który został przekazany dodone funkcji (patrz 1.). Tak więc cały obiekt jest odzyskiwany za pomocą tego klucza. Ten klucz jest tutaj identyfikatorem użytkownika (kluczem może być dowolny klucz obiektu użytkownika, np. Nazwa, adres e-mail itp.). WdeserializeUser tym kluczu jest dopasowany do macierzy pamięci / bazy danych lub dowolnego zasobu danych.

Pobrany obiekt jest dołączany do obiektu żądania jako req.user

Wizualny przepływ

passport.serializeUser(function(user, done) {
    done(null, user.id);
});              
                  
                 
                 └─────────────────┬──→ saved to session
                                       req.session.passport.user = {id: '..'}
                                   
                                              
passport.deserializeUser(function(id, done) {
                   ┌───────────────┘
                   
                    
    User.findById(id, function(err, user) {
        done(err, user);
    });            └──────────────→ user object attaches to the request as req.user   
});
AB
źródło
2
Więc jest user.idzapisywany jako req.session.passport.userlub usersam jest przechowywany jakoreq.session.passport.user
Anubhav,
@AB Napisałem kod, aby znaleźć użytkownika z identyfikatora, który został przekazany do deserializacji metody jako pierwszego parametru. Ale w każdym żądaniu pobiera użytkownika z bazy danych. Powoduje to utratę wydajności dla db. Co jeszcze powinienem napisać, aby deserializować funkcję, aby sprawdzić, czy istnieje ona w sesji, czy nie?
uzay95
2
@AB Nie rozumiem, co sugerujesz uzay95. Więc w mojej sesji mam tylko user._id. Ale przy każdym żądaniu muszę użyć tego identyfikatora, aby dokonać deserializacji z bazy danych znanej jako findUserByID, a to spowoduje umieszczenie go w pliku req.user. Jak mogę uniknąć takiego połączenia na każde żądanie?
Zanko
10
@Zanko Możesz umieścić cały obiekt użytkownika w danych sesji, ale zwykle nie jest to dobry pomysł, ponieważ może mieć inne skutki uboczne. Na przykład, gdy użytkownik zaktualizuje swoją nazwę użytkownika, musisz również zaktualizować dane sesji, w przeciwnym razie otrzymasz bilety z powodu „funkcji zepsutej zmiany nazwy”. To stosunkowo nieszkodliwy przykład. To samo może się zdarzyć z bitami uprawnień lub danymi wrażliwymi na równi (Ups ...). Zasadniczo te same problemy, na które zawsze natrafisz, jeśli masz zduplikowane dane. TL; DR - Nie rób tego.
Max Truxa,
1
Jeśli się nie mylę, req.session.passport.user = {id: '..'}część diagramu jest nieco wyłączona i powinna być req.session.passport.user = 785352zamiast tego, gdzie 785352jest user.id. Mam problem z zalogowaniem się do konsoli, aby to udowodnić, ale wygląda na to, że miałoby to sens. Kiedy dzwonisz done(null, user.id);, warto wziąć drugi argument - user.idw tym przypadku - i przypisać go req.session.passport.user, zamiast przypisywać go req.session.passport.user.id. Bo co jeśli zamiast tego przejdziesz user? req.sesssion.passport.user.id = usernie miałoby sensu
Adam Zerner
21

Dla każdego, kto używa Koa i paszportu koa :

Wiedz, że klucz dla zestawu użytkowników w metodzie serializeUser (często unikalny identyfikator dla tego użytkownika) będzie przechowywany w:

this.session.passport.user

Po ustawieniu w done(null, user)deserializeUser, gdzie „użytkownik” to jakiś obiekt użytkownika z bazy danych:

this.req.user LUB this.passport.user

z jakiegoś powodu this.userkontekst Koa nigdy nie jest ustawiany, gdy wywołasz metodę done (null, user) w metodzie deserializeUser.

Możesz więc napisać własne oprogramowanie pośrednie po wywołaniu app.use (passport.session ()), aby umieścić je w this.user w następujący sposób:

app.use(function * setUserInContext (next) {
  this.user = this.req.user
  yield next
})

Jeśli nie masz pewności, jak działa serializeUser i deserializeUser, po prostu uderz mnie na Twitterze. @yvanscher

yvanscher
źródło
Przepraszam za nekropolię tutaj, ale teraz mam obawy po przeczytaniu wyjaśnienia deserializowanego. Wysłałem pytanie na ten temat tutaj na SO: stackoverflow.com/questions/54154047/…
Peter Kellner
Super pomocny, ale wciąż występują problemy z odczytaniem użytkownika z innych tras. Czy ktoś może mi pomóc tutaj? stackoverflow.com/questions/60709882/…
Harry Lincoln