ทำความเข้าใจกับหนังสือเดินทางทำให้เป็นอันดับซีเรียล


337

คุณจะอธิบายเวิร์กโฟลว์ของวิธีการทำให้เป็นอันดับและวิธีการซีเรียลไลเซชันของ Passport อย่างไรให้กับคนธรรมดา

  1. ไม่อยู่ที่ไหนuser.idไปหลังจากที่passport.serializeUserได้รับการเรียกว่า?

  2. เรากำลังโทรหาpassport.deserializeUserหลังจากนั้นมันเข้ากับกระแสงานได้ที่ไหน?

    // 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);
        });
    });

ฉันยังคงพยายามห่อหัวไว้ ฉันมีแอพที่ใช้งานได้อย่างสมบูรณ์และไม่พบข้อผิดพลาดใด ๆ

ฉันแค่อยากจะเข้าใจว่าเกิดอะไรขึ้นที่นี่?

ความช่วยเหลือใด ๆ ที่ชื่นชม

คำตอบ:


452
  1. ไม่อยู่ที่ไหนuser.idไปหลังจากที่passport.serializeUserได้รับการเรียกว่า?

ID ผู้ใช้ (คุณระบุเป็นอาร์กิวเมนต์ที่สองของdoneฟังก์ชัน) จะถูกบันทึกในเซสชันและใช้ในภายหลังเพื่อดึงข้อมูลวัตถุทั้งหมดผ่านdeserializeUserฟังก์ชั่น

serializeUserกำหนดข้อมูลของวัตถุผู้ใช้ที่ควรเก็บไว้ในเซสชั่น ผลของวิธีการ serializeUser req.session.passport.user = {}ที่อยู่ติดกับเซสชั่นเป็น เช่นที่นี่มันจะเป็น (ในขณะที่เราให้รหัสผู้ใช้เป็นกุญแจสำคัญ)req.session.passport.user = {id: 'xyz'}

  1. เรากำลังโทรหาpassport.deserializeUserหลังจากนั้นมันเข้ากับกระแสงานได้ที่ไหน?

อาร์กิวเมนต์แรกของdeserializeUserสอดคล้องกับคีย์ของวัตถุผู้ใช้ที่ได้รับdoneฟังก์ชั่น (ดู 1) ดังนั้นวัตถุทั้งหมดของคุณจะถูกเรียกคืนด้วยความช่วยเหลือของกุญแจนั้น กุญแจนั่นคือรหัสผู้ใช้ (กุญแจสามารถเป็นกุญแจใด ๆ ของวัตถุผู้ใช้เช่นชื่ออีเมล ฯลฯ ) ในdeserializeUserคีย์นั้นถูกจับคู่กับในหน่วยความจำอาร์เรย์ / ฐานข้อมูลหรือทรัพยากรข้อมูลใด ๆ

วัตถุที่นำมาแนบกับวัตถุคำขอเป็น req.user

การไหลของภาพ

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   
});

2
ดังนั้นจะuser.idบันทึกเป็นreq.session.passport.userหรือถูกuserเก็บไว้เป็นreq.session.passport.user
Anubhav

@AB ฉันเขียนโค้ดเพื่อค้นหาผู้ใช้จาก id ซึ่งถูกส่งผ่านไปยังวิธีดีซีเรียลไลซ์เป็นพารามิเตอร์แรก แต่ในทุกคำขอมันจะดึงผู้ใช้จาก db ทำให้สูญเสียประสิทธิภาพสำหรับ db ฉันควรเขียนฟังก์ชัน deserialize เพื่อตรวจสอบว่ามีอยู่ในเซสชันหรือไม่
uzay95

2
@AB ฉันไม่เข้าใจสิ่งที่คุณแนะนำให้กับ uzay95 ดังนั้นในเซสชั่นของฉันฉันมีเพียง user._id แต่ทุกครั้งที่มีการร้องขอฉันต้องใช้รหัสนั้นเพื่อทำการ deserialized จากฐานข้อมูล aka findUserByID และจะนำไปใส่ใน req.user ฉันจะหลีกเลี่ยงการโทรตามคำขอทุกครั้งได้อย่างไร
Zanko

10
@Zanko คุณสามารถใส่วัตถุผู้ใช้ทั้งหมดลงในข้อมูลเซสชั่นได้ แต่โดยทั่วไปแล้วมันไม่ได้เป็นความคิดที่ดีเพราะมันสามารถมีผลข้างเคียงอื่น ๆ ตัวอย่างเช่นเมื่อผู้ใช้อัปเดตชื่อผู้ใช้ของเขา / เธอคุณต้องอัปเดตข้อมูลเซสชันมิฉะนั้นคุณจะได้รับตั๋วเนื่องจาก "คุณสมบัติการเปลี่ยนชื่อที่ใช้งานไม่ได้" นั่นเป็นตัวอย่างที่ไม่เป็นอันตราย เดียวกันอาจเกิดขึ้นกับบิตสิทธิ์หรือข้อมูลที่สำคัญเท่ากัน (โอ๊ะโอ ... ) เป็นหลักปัญหาเดียวกันคุณมักจะพบถ้าคุณมีข้อมูลที่ซ้ำกัน TL; DR - อย่าทำ
Max Truxa

1
ถ้าฉันไม่ผิดที่req.session.passport.user = {id: '..'}เป็นส่วนหนึ่งของแผนภาพเล็กน้อยปิดและควรจะreq.session.passport.user = 785352แทนซึ่งเป็น785352 user.idฉันมีปัญหาในการบันทึกคอนโซลเพื่อพิสูจน์ แต่ดูเหมือนว่าเหมาะสมแล้ว เมื่อคุณเรียกdone(null, user.id);มันจะให้ความรู้สึกที่จะใช้อาร์กิวเมนต์ที่สอง - user.idในกรณีนี้ - และกำหนดให้แทนการกำหนดค่าให้กับreq.session.passport.user req.session.passport.user.idเพราะถ้าคุณผ่านไปแทนuserล่ะ req.sesssion.passport.user.id = userจะไม่สมเหตุสมผล
Adam Zerner

21

สำหรับใครก็ตามที่ใช้ Koa และkoa-passport :

รู้ว่ากุญแจสำหรับผู้ใช้ที่ตั้งค่าในวิธี serializeUser (มักจะเป็นรหัสเฉพาะสำหรับผู้ใช้นั้น) จะถูกเก็บไว้ใน:

this.session.passport.user

เมื่อคุณตั้งค่าในdone(null, user)deserializeUser โดยที่ 'ผู้ใช้' คือวัตถุผู้ใช้บางส่วนจากฐานข้อมูลของคุณ:

this.req.user หรือ this.passport.user

ด้วยเหตุผลบางอย่างthis.userบริบท Koa จะไม่ได้รับการตั้งค่าเมื่อคุณเรียกใช้ (null, ผู้ใช้) ใน deserializeUser ของคุณ

เพื่อให้คุณสามารถเขียนมิดเดิลแวร์ของคุณเองหลังจากการเรียกใช้ app.use (passport.session ()) เพื่อวางไว้ใน this.user ดังนี้:

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

หากคุณไม่ชัดเจนว่า serializeUser และ deserializeUser ทำงานอย่างไรให้กดฉันบนทวิตเตอร์ @yvanscher


ขออภัยที่ necroposting ที่นี่ แต่ฉันมีความกังวลในขณะนี้หลังจากอ่านคำอธิบายที่หมดความจำเป็น ฉันโพสต์คำถามเกี่ยวกับสิ่งนี้ที่นี่ใน SO: stackoverflow.com/questions/54154047/…
Peter Kellner

มีประโยชน์มาก แต่ก็ยังมีปัญหาบางอย่างที่อ่านผู้ใช้จากเส้นทางอื่น มีใครช่วยฉันที่นี่ได้บ้าง stackoverflow.com/questions/60709882/…
Harry Lincoln
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.