JWT (JSON Web Token) การยืดเวลาหมดอายุโดยอัตโนมัติ


509

ฉันต้องการใช้การตรวจสอบตาม JWT กับ REST API ใหม่ของเรา แต่เนื่องจากการหมดอายุถูกกำหนดในโทเค็นจึงเป็นไปได้ที่จะยืดออกโดยอัตโนมัติหรือไม่ ฉันไม่ต้องการให้ผู้ใช้ลงชื่อเข้าใช้ทุก ๆ X นาทีหากพวกเขาใช้แอปพลิเคชันในช่วงเวลานั้นอย่างแข็งขัน นั่นจะเป็น UX ขนาดใหญ่ที่ล้มเหลว

แต่การยืดเวลาการหมดอายุสร้างโทเค็นใหม่ (และโทเค็นเก่ายังคงใช้ได้จนกว่าจะหมดอายุ) และสร้างโทเค็นใหม่หลังจากคำขอแต่ละครั้งฟังดูไร้สาระสำหรับฉัน ฟังดูเหมือนปัญหาด้านความปลอดภัยเมื่อมีโทเค็นมากกว่าหนึ่งอันถูกต้องในเวลาเดียวกัน แน่นอนฉันสามารถยกเลิกใช้เก่าใช้บัญชีดำ แต่ฉันจะต้องเก็บโทเค็น และข้อดีอย่างหนึ่งของ JWT ก็คือไม่มีที่เก็บข้อมูล

ฉันพบวิธีที่ Auth0 แก้ไขได้ พวกเขาใช้โทเค็น JWT ไม่เพียง แต่ยังเป็นโทเค็นรีเฟรช: https://docs.auth0.com/refresh-token

แต่อีกครั้งในการดำเนินการนี้ (ไม่มี Auth0) ฉันต้องจัดเก็บโทเค็นการรีเฟรชและรักษาวันหมดอายุไว้ แล้วประโยชน์ที่แท้จริงคืออะไร? ทำไมไม่มีโทเค็นเดียวเท่านั้น (ไม่ใช่ JWT) และเก็บการหมดอายุไว้บนเซิร์ฟเวอร์

มีตัวเลือกอื่น ๆ อีกไหม? การใช้ JWT ไม่เหมาะกับสถานการณ์นี้หรือไม่?


1
ที่จริงแล้วอาจไม่มีปัญหาด้านความปลอดภัยกับโทเค็นที่ถูกต้องจำนวนมากในครั้งเดียว ... จริง ๆ แล้วมีโทเค็นที่ถูกต้องจำนวนไม่ จำกัด ... ดังนั้นทำไมจึงมีโทเค็นรีเฟรชแล้ว ฉันจะสร้างมันขึ้นมาใหม่หลังจากการร้องขอแต่ละครั้งจริง ๆ แล้วมันไม่ควรมีปัญหา
maryo

1
สำหรับสปาชำระเงินโพสต์บล็อกของฉัน: blog.wong2.me/2017/02/20/refresh-auth0-token-in-spa
wong2

2
@ มารีโอฉันคิดว่าการมี JWT ที่ยังไม่ได้ใช้งานนับร้อยหรือนับพันที่ใช้งานไม่ได้อยู่ที่นั่น ณ เวลาใดก็ตามจะเพิ่มพื้นที่การโจมตีของคุณและเป็นความเสี่ยงด้านความปลอดภัย ในความคิดของฉัน JWT ควรได้รับการออกมาอย่างระมัดระวังเนื่องจากพวกมันสามารถเข้าถึงโทเค็นได้ด้วยกุญแจในปราสาท
java-addict301

คำตอบ:


590

ฉันทำงานที่ Auth0 และฉันมีส่วนร่วมในการออกแบบคุณสมบัติโทเค็นการรีเฟรช

ทุกอย่างขึ้นอยู่กับประเภทของแอปพลิเคชันและนี่คือแนวทางที่เราแนะนำ

เว็บแอปพลิเคชัน

รูปแบบที่ดีคือการรีเฟรชโทเค็นก่อนที่จะหมดอายุ

ตั้งค่าการหมดอายุโทเค็นเป็นหนึ่งสัปดาห์และรีเฟรชโทเค็นทุกครั้งที่ผู้ใช้เปิดเว็บแอปพลิเคชันและทุก ๆ หนึ่งชั่วโมง หากผู้ใช้ไม่ได้เปิดแอปพลิเคชั่นนานกว่าหนึ่งสัปดาห์พวกเขาจะต้องลงชื่อเข้าใช้อีกครั้งและนี่เป็นเว็บแอปพลิเคชัน UX ที่ยอมรับได้

ในการรีเฟรชโทเค็น API ของคุณจำเป็นต้องมีจุดปลายใหม่ที่ได้รับที่ถูกต้องไม่หมดอายุ JWT และส่งคืน JWT ที่ลงชื่อแล้วเดียวกันด้วยฟิลด์การหมดอายุใหม่ จากนั้นเว็บแอปพลิเคชันจะจัดเก็บโทเค็นที่ใดที่หนึ่ง

แอปพลิเคชั่นมือถือ / เนทีฟ

แอปพลิเคชั่นส่วนใหญ่จะทำการล็อกอินเพียงครั้งเดียวเท่านั้น

แนวคิดคือโทเค็นการรีเฟรชไม่มีวันหมดอายุและสามารถแลกเปลี่ยนเป็น JWT ที่ถูกต้องได้เสมอ

ปัญหาเกี่ยวกับโทเค็นที่ไม่หมดอายุคือไม่เคยหมายความว่าไม่เคย คุณจะทำอย่างไรถ้าคุณทำโทรศัพท์หาย ดังนั้นจึงจำเป็นต้องระบุตัวตนของผู้ใช้อย่างใดและแอปพลิเคชันจะต้องมีวิธีในการเพิกถอนการเข้าถึง เราตัดสินใจใช้ชื่ออุปกรณ์เช่น "maryo's iPad" จากนั้นผู้ใช้สามารถไปที่แอปพลิเคชันและเพิกถอนการเข้าถึง "maryo's iPad"

อีกวิธีหนึ่งคือการยกเลิกโทเค็นการรีเฟรชในเหตุการณ์เฉพาะ เหตุการณ์ที่น่าสนใจกำลังเปลี่ยนรหัสผ่าน

เราเชื่อว่า JWT ไม่มีประโยชน์สำหรับกรณีการใช้งานเหล่านี้ดังนั้นเราจึงใช้สตริงที่สร้างแบบสุ่มและเราเก็บไว้ที่ด้านข้างของเรา


42
สำหรับวิธีที่แนะนำให้ใช้กับเว็บแอปพลิเคชันหากโทเค็นนั้นถูกต้องเป็นเวลาหนึ่งสัปดาห์เราไม่เกี่ยวข้องกับใครบางคนที่ขัดขวางโทเค็นแล้วจึงสามารถใช้งานได้เป็นเวลานาน คำเตือน: ฉันไม่รู้ว่าฉันกำลังพูดถึงอะไร
user12121234

30
@wbeange ใช่การสกัดกั้นเป็นปัญหาแม้แต่กับคุกกี้ คุณควรใช้ https
José F. Romaniello

15
@ JoséF.Romanielloในตัวอย่างเว็บแอปพลิเคชันของคุณทุกอย่างสมเหตุสมผลสำหรับฉันยกเว้นต้องเก็บโทเค็น ฉันคิดว่าความงามของ JWT คือการพิสูจน์ตัวตนแบบไร้รัฐ - หมายความว่าเว็บแอปพลิเคชันไม่ต้องเก็บโทเค็นขณะที่ลงชื่อ ฉันคิดว่าเซิร์ฟเวอร์สามารถตรวจสอบความถูกต้องของโทเค็นตรวจสอบให้แน่ใจว่าอยู่ในช่วงเวลาที่หมดอายุแล้วจึงออกโทเค็น JWT ที่ต่ออายุใหม่ คุณช่วยอธิบายเรื่องนี้ให้ละเอียดหน่อยได้ไหม? บางทีฉันแค่ไม่เข้าใจ JWT เพียงพอ
Lo-Tan

7
คำถาม / ข้อสงสัยสองข้อ: 1- กรณีแอปพลิเคชันเว็บ: เหตุใดโทเค็นที่หมดอายุจะไม่ได้รับอนุญาตให้รีเฟรช สมมติว่าเราตั้งค่าการหมดอายุสั้น ๆ (1 ชั่วโมง) และทำการโทรไปยังเซิร์ฟเวอร์ด้านหลังเมื่อโทเค็นหมดอายุตามที่คุณพูด 2- มีความกังวลเรื่องความปลอดภัยหรือไม่ในการจัดเก็บรหัสผ่านที่แฮช (ด้วยเกลือแบบสุ่ม) ในโทเค็น แนวคิดคือถ้ามีเซิร์ฟเวอร์ส่วนหลังสามารถตรวจสอบกับรหัสผ่านที่เก็บไว้ในฐานข้อมูลเมื่อมีการขอต่ออายุและปฏิเสธคำขอหากรหัสผ่านไม่ตรงกัน สิ่งนี้จะครอบคลุมถึงการเปลี่ยนรหัสผ่านของแอปมือถือ / เนทีฟทำให้สามารถขยายโซลูชันไปยังเคสการใช้งานมือถือ
psamaan

7
-1 การเปิดเผย API สาธารณะซึ่งสุ่มสัญญาณโทเค็นใด ๆ เพื่อขยายระยะเวลาการตรวจสอบความถูกต้องอีกครั้ง ตอนนี้โทเค็นทั้งหมดของคุณมีหมดอายุไม่สิ้นสุดที่มีประสิทธิภาพ การกระทำของการลงนามโทเค็นควรรวมถึงการตรวจสอบความถูกต้องที่เหมาะสมสำหรับการเรียกร้องแต่ละครั้งและทุกครั้งที่ทำในโทเค็นนั้นในเวลาที่ลงนาม
Phil

69

ในกรณีที่คุณจัดการรับรองความถูกต้องด้วยตัวเอง (เช่นไม่ใช้ผู้ให้บริการอย่าง Auth0) รายการต่อไปนี้อาจใช้ได้:

  1. ออกโทเค็น JWT ที่มีระยะเวลาสั้น ๆ พูด 15 นาที
  2. แอปพลิเคชันตรวจสอบวันที่โทเค็นหมดอายุก่อนการทำธุรกรรมใด ๆ ที่ต้องใช้โทเค็น (โทเค็นมีวันหมดอายุ) ถ้าโทเค็นหมดอายุแล้วอันดับแรกจะขอให้ API 'รีเฟรช' โทเค็น (ซึ่งจะทำกับโปร่งใส UX)
  3. API ได้รับคำขอรีเฟรชโทเค็น แต่ก่อนอื่นตรวจสอบฐานข้อมูลผู้ใช้เพื่อดูว่ามีการตั้งค่าสถานะ 'reauth' กับโปรไฟล์ผู้ใช้นั้นหรือไม่ (โทเค็นสามารถมี ID ผู้ใช้) หากมีการตั้งค่าสถานะการรีเฟรชโทเค็นจะถูกปฏิเสธมิฉะนั้นจะมีการออกโทเค็นใหม่
  4. ทำซ้ำ

การตั้งค่าสถานะ 'reauth' ในแบ็กเอนด์ฐานข้อมูลจะถูกตั้งค่าเมื่อผู้ใช้รีเซ็ตรหัสผ่าน การตั้งค่าสถานะจะถูกลบเมื่อผู้ใช้เข้าสู่ระบบในครั้งต่อไป

นอกจากนี้สมมติว่าคุณมีนโยบายที่ผู้ใช้จะต้องเข้าสู่ระบบอย่างน้อยทุก ๆ 72 ชั่วโมง ในกรณีดังกล่าวตรรกะการรีเฟรชโทเค็น API ของคุณจะตรวจสอบวันที่เข้าสู่ระบบครั้งล่าสุดของผู้ใช้จากฐานข้อมูลผู้ใช้และปฏิเสธ / อนุญาตให้รีเฟรชโทเค็นบนพื้นฐานนั้น


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

6
@ user2924127 ไม่มีวิธีตรวจสอบสิทธิ์ที่สมบูรณ์แบบและจะมีการแลกเปลี่ยนเสมอ หากผู้โจมตีอยู่ในฐานะที่จะ 'ขโมยโทเค็นของคุณ' คุณอาจมีปัญหามากขึ้นที่ต้องกังวล การตั้งค่าโทเค็นอายุการใช้งานสูงสุดจะเป็นประโยชน์บิดไปด้านบน
IanB

27
แทนที่จะมีฟิลด์อื่นในฐานข้อมูลให้ตั้งค่าสถานะใหม่คุณสามารถรวมสำหรับแฮช (bcrypt_password_hash) ในโทเค็น จากนั้นเมื่อรีเฟรชโทเค็นคุณเพียงยืนยันว่าแฮช (bcrypt_password_hash) เท่ากับค่าจากโทเค็น เพื่อที่จะปฏิเสธการรีเฟรชโทเค็นคุณต้องทำการอัพเดตแฮ็กรหัสผ่าน
bas

4
@ คือความคิดในการปรับให้เหมาะสมและประสิทธิภาพฉันคิดว่าการตรวจสอบรหัสผ่านแฮชจะซ้ำซ้อนและมีความเกี่ยวข้องกับเซิร์ฟเวอร์มากกว่า เพิ่มขนาดของโทเค็นเพื่อให้ บริษัท / การตรวจสอบความถูกต้องใช้เวลามากขึ้น การคำนวณการแฮชเพิ่มเติมสำหรับเซิร์ฟเวอร์สำหรับรหัสผ่าน ด้วยวิธีการพิเศษในฟิลด์ที่คุณเพิ่งตรวจสอบในการคำนวณใหม่ด้วยบูลีนที่เรียบง่าย การอัพเดต Db นั้นใช้บ่อยสำหรับฟิลด์พิเศษ แต่จะมีการรีเฟรชโทเค็นบ่อยขึ้น และคุณจะได้รับบริการเสริมในการเข้าสู่ระบบของแต่ละบุคคลสำหรับเซสชันใด ๆ ที่มีอยู่ (มือถือเว็บ ฯลฯ )
le0diaz

6
ฉันคิดว่าความคิดเห็นแรกจาก user2924127 นั้นผิดจริง เมื่อเปลี่ยนรหัสผ่านบัญชีจะถูกทำเครื่องหมายว่าต้องการการตรวจสอบความถูกต้องอีกครั้งดังนั้นโทเค็นที่หมดอายุที่มีอยู่จะไม่ถูกต้อง
Ralph

15

ฉันลังเลที่จะย้ายแอปพลิเคชั่นของเราไปที่ HTML5 ด้วย RESTful apis ในแบ็กเอนด์ ทางออกที่ฉันเกิดขึ้นคือ:

  1. ลูกค้าออกด้วยโทเค็นที่มีเวลาเซสชัน 30 นาที (หรือเวลาเซสชันฝั่งเซิร์ฟเวอร์ปกติใด ๆ ) เมื่อเข้าสู่ระบบที่ประสบความสำเร็จ
  2. ตัวจับเวลาฝั่งไคลเอ็นต์ถูกสร้างขึ้นเพื่อเรียกใช้บริการเพื่อต่ออายุโทเค็นก่อนเวลาหมดอายุ โทเค็นใหม่จะแทนที่ที่มีอยู่ในการโทรในอนาคต

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

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

ฉันไม่ชอบความคิดในการตั้งค่าการหมดอายุที่ยาวนานดังนั้นวิธีการนี้อาจทำงานได้ไม่ดีกับแอปพลิเคชันดั้งเดิมที่ต้องมีการตรวจสอบสิทธิ์น้อยกว่าบ่อยครั้ง


1
จะทำอย่างไรถ้าคอมพิวเตอร์ถูกระงับ / สลีป ตัวจับเวลาจะยังคงนับจนถึงวันหมดอายุ แต่โทเค็นนั้นหมดอายุแล้วจริง ๆ ตัวจับเวลาไม่ทำงานในสถานการณ์นี้
อเล็กซ์ Parij

@AlexParij คุณจะเปรียบเทียบกับเวลาที่กำหนดบางอย่างเช่นนี้: stackoverflow.com/a/35182296/1038456
Aparajita

2
การอนุญาตให้ไคลเอนต์ร้องขอโทเค็นใหม่ที่มีวันหมดอายุที่ต้องการมีกลิ่นเหมือนกับความเสี่ยงด้านความปลอดภัยสำหรับฉัน
java-addict301

14

โซลูชันทางเลือกสำหรับการทำให้ JWT ใช้ไม่ได้โดยไม่มีที่เก็บข้อมูลความปลอดภัยเพิ่มเติมใด ๆ บนแบ็กเอนด์คือการใช้jwt_versionคอลัมน์จำนวนเต็มใหม่ในตารางผู้ใช้ หากผู้ใช้ต้องการออกจากระบบหรือหมดอายุโทเค็นที่มีอยู่พวกเขาเพียงแค่เพิ่มjwt_versionฟิลด์

เมื่อสร้าง JWT ใหม่ให้เข้ารหัสjwt_versionลงใน JWT เพย์โหลดทางเลือกการเพิ่มมูลค่าล่วงหน้าหาก JWT ใหม่ควรแทนที่อื่น ๆ ทั้งหมด

เมื่อตรวจสอบความถูกต้องของ JWT jwt_versionจะมีการเปรียบเทียบฟิลด์ข้างกับuser_idและการให้สิทธิ์จะได้รับเฉพาะเมื่อตรง


1
มีปัญหากับอุปกรณ์หลายเครื่อง เป็นหลักถ้าคุณออกจากระบบบนอุปกรณ์หนึ่งมันออกจากระบบทุกที่ ขวา?
Sam Washburn

4
เฮ้นั่นอาจไม่ใช่ "ปัญหา" ขึ้นอยู่กับความต้องการของคุณ แต่คุณพูดถูก สิ่งนี้ไม่สนับสนุนการจัดการเซสชันต่ออุปกรณ์
Ollie Bennett

นี่ไม่ได้หมายความว่าจะต้องเก็บ jwt_version ฝั่งเซิร์ฟเวอร์เพื่อให้รูปแบบการรับรองความถูกต้องกลายเป็น "session-like" และเอาชนะวัตถุประสงค์พื้นฐานของ JWT
ChetPrickles

8

คำถามที่ดี - และมีความมั่งคั่งของข้อมูลในคำถามนั้น

บทความรีเฟรชโทเค็น: เมื่อใดที่จะใช้พวกเขาและวิธีที่พวกเขาโต้ตอบกับ JWTจะให้แนวคิดที่ดีสำหรับสถานการณ์นี้ บางจุดคือ: -

  • รีเฟรชโทเค็นนำข้อมูลที่จำเป็นเพื่อรับโทเค็นการเข้าถึงใหม่
  • โทเค็นรีเฟรชยังสามารถหมดอายุ แต่ค่อนข้างยาว
  • โทเค็นการรีเฟรชมักขึ้นอยู่กับข้อกำหนดในการจัดเก็บข้อมูลที่เข้มงวดเพื่อให้แน่ใจว่าไม่มีการรั่วไหล
  • พวกเขายังสามารถขึ้นบัญชีดำโดยเซิร์ฟเวอร์การอนุญาต

ดูที่auth0 / angular-jwt angularjs ด้วย

สำหรับ Web API อ่านเปิดใช้งานโทเค็นรีเฟรช OAuth ในแอป AngularJS โดยใช้ ASP .NET Web API 2 และ Owin


บางทีฉันอาจจะอ่านผิด ... แต่บทความที่มีชื่อที่เริ่มต้นเป็น "Refresh Tokens ... " ไม่มีเนื้อหาเกี่ยวกับโทเค็นการรีเฟรชยกเว้นสิ่งที่คุณพูดถึงที่นี่
Ievgen Martynov

8

จริง ๆ แล้วฉันใช้สิ่งนี้ใน PHP โดยใช้ไคลเอนต์ Guzzle เพื่อสร้างไลบรารีไคลเอ็นต์สำหรับ api แต่แนวคิดควรใช้กับแพลตฟอร์มอื่นได้

โดยพื้นฐานแล้วฉันออกโทเค็นสองอันสั้น (5 นาที) หนึ่งและยาวหนึ่งที่หมดอายุหลังจากหนึ่งสัปดาห์ ไลบรารีไคลเอ็นต์ใช้มิดเดิลแวร์เพื่อรีเฟรชโทเค็นสั้น ๆ หนึ่งครั้งหากได้รับการตอบสนอง 401 สำหรับการร้องขอบางอย่าง จากนั้นจะลองคำขอเดิมอีกครั้งและหากสามารถรีเฟรชได้รับการตอบสนองที่ถูกต้องให้ผู้ใช้อย่างโปร่งใส หากล้มเหลวก็จะส่ง 401 ถึงผู้ใช้

หากโทเค็นสั้นหมดอายุแล้ว แต่ยังคงเป็นของแท้และโทเค็นแบบยาวนั้นถูกต้องและเป็นของจริงโทเค็นแบบสั้นจะใช้จุดปลายพิเศษบนบริการที่โทเค็นแบบยาวรับรองความถูกต้อง (นี่เป็นสิ่งเดียวที่สามารถใช้ได้) จากนั้นจะใช้โทเค็นสั้น ๆ เพื่อรับโทเค็นแบบยาวใหม่ซึ่งจะขยายไปอีกสัปดาห์ทุกครั้งที่รีเฟรชโทเค็นสั้น

วิธีนี้ยังช่วยให้เราสามารถยกเลิกการเข้าถึงได้ภายในเวลาไม่เกิน 5 นาทีซึ่งเป็นที่ยอมรับสำหรับการใช้งานของเราโดยไม่ต้องจัดเก็บรายการโทเค็นบัญชีดำ

การแก้ไขล่าช้า: การอ่านอีกครั้งในเดือนนี้หลังจากที่ฉันยังสดอยู่ในหัวฉันควรชี้ให้เห็นว่าคุณสามารถเพิกถอนการเข้าถึงได้เมื่อรีเฟรชโทเค็นสั้น ๆ เพราะให้โอกาสในการโทรที่มีราคาแพงกว่า (เช่นโทรไปยังฐานข้อมูล ถูกแบน) โดยไม่จ่ายค่าโทรทุกครั้งที่เข้าใช้บริการของคุณ


8

ด้านล่างเป็นขั้นตอนในการเพิกถอนโทเค็นการเข้าถึง JWT ของคุณ:

1) เมื่อคุณเข้าสู่ระบบส่ง 2 โทเค็น (การเข้าถึงโทเค็นรีเฟรชโทเค็น) เพื่อตอบสนองต่อลูกค้า
2) โทเค็นการเข้าถึงจะมีเวลาหมดอายุน้อยลงและรีเฟรชจะมีเวลาหมดอายุที่ยาวนาน
3) ไคลเอนต์ (Front end) จะเก็บโทเค็นการรีเฟรชในที่เก็บข้อมูลในเครื่องและการเข้าถึงโทเค็นในคุกกี้
4) ลูกค้าจะใช้โทเค็นการเข้าถึงสำหรับการเรียก apis แต่เมื่อหมดอายุให้เลือกโทเค็นการรีเฟรชจากที่จัดเก็บในตัวเครื่องแล้วโทรหาเซิร์ฟเวอร์รับรองความถูกต้องเพื่อรับโทเค็นใหม่
5) เซิร์ฟเวอร์รับรองความถูกต้องของคุณจะมี api เปิดเผยซึ่งจะยอมรับโทเค็นการรีเฟรชและตรวจสอบความถูกต้องและส่งคืนโทเค็นการเข้าถึงใหม่
6) เมื่อรีเฟรชโทเค็นหมดอายุผู้ใช้จะถูกออกจากระบบ

โปรดแจ้งให้เราทราบหากคุณต้องการรายละเอียดเพิ่มเติมฉันสามารถแชร์รหัส (บูต Java + Spring) ได้เช่นกัน


คุณช่วยแบ่งปันลิงค์โครงการของคุณได้ไหมถ้ามีใน GitHub?
อรุณคูมาร์ N


6

JWT-autorefresh

หากคุณใช้โหนด (React / Redux / Universal JS) คุณสามารถติดตั้งnpm i -S jwt-autorefreshได้

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

ตัวอย่างการใช้งานเต็มรูปแบบ

import autorefresh from 'jwt-autorefresh'

/** Events in your app that are triggered when your user becomes authorized or deauthorized. */
import { onAuthorize, onDeauthorize } from './events'

/** Your refresh token mechanism, returning a promise that resolves to the new access tokenFunction (library does not care about your method of persisting tokens) */
const refresh = () => {
  const init =  { method: 'POST'
                , headers: { 'Content-Type': `application/x-www-form-urlencoded` }
                , body: `refresh_token=${localStorage.refresh_token}&grant_type=refresh_token`
                }
  return fetch('/oauth/token', init)
    .then(res => res.json())
    .then(({ token_type, access_token, expires_in, refresh_token }) => {
      localStorage.access_token = access_token
      localStorage.refresh_token = refresh_token
      return access_token
    })
}

/** You supply a leadSeconds number or function that generates a number of seconds that the refresh should occur prior to the access token expiring */
const leadSeconds = () => {
  /** Generate random additional seconds (up to 30 in this case) to append to the lead time to ensure multiple clients dont schedule simultaneous refresh */
  const jitter = Math.floor(Math.random() * 30)

  /** Schedule autorefresh to occur 60 to 90 seconds prior to token expiration */
  return 60 + jitter
}

let start = autorefresh({ refresh, leadSeconds })
let cancel = () => {}
onAuthorize(access_token => {
  cancel()
  cancel = start(access_token)
})

onDeauthorize(() => cancel())

ข้อจำกัดความรับผิดชอบ: ฉันเป็นผู้ดูแล


คำถามเกี่ยวกับเรื่องนี้ฉันเห็นฟังก์ชั่นถอดรหัสที่ใช้ มันถือว่า JWT สามารถถอดรหัสได้โดยไม่ต้องใช้ความลับหรือไม่? ใช้กับ JWT ที่เซ็นชื่อด้วยความลับได้หรือไม่?
Gian Franco Zabarino

3
ใช่การถอดรหัสเป็นการถอดรหัสแบบไคลเอ็นต์เท่านั้นและไม่ควรทราบถึงความลับ ความลับถูกใช้เพื่อลงนาม JWT โทเค็นฝั่งเซิร์ฟเวอร์เพื่อตรวจสอบว่าลายเซ็นของคุณถูกใช้เพื่อสร้าง JWT แต่เดิมและไม่ควรใช้จากไคลเอนต์ ความมหัศจรรย์ของ JWT คือส่วนของข้อมูลที่สามารถถอดรหัสลูกค้าฝั่งและการเรียกร้องภายในสามารถใช้ในการสร้าง UI ของคุณโดยไม่มีความลับ สิ่งเดียวที่jwt-autorefreshถอดรหัสได้คือการแยกการexpอ้างสิทธิ์เพื่อให้สามารถกำหนดได้ว่าจะกำหนดเวลาการรีเฟรชครั้งต่อไปนานแค่ไหน
cchamberlain

1
โอ้ดีที่รู้บางอย่างไม่เข้าท่า แต่ตอนนี้ก็พอแล้ว ขอบคุณสำหรับคำตอบ.
Gian Franco Zabarino

4

ฉันแก้ไขปัญหานี้โดยการเพิ่มตัวแปรในข้อมูลโทเค็น:

softexp - I set this to 5 mins (300 seconds)

ฉันตั้งค่าexpiresInตัวเลือกเป็นเวลาที่ต้องการก่อนที่ผู้ใช้จะถูกบังคับให้เข้าสู่ระบบอีกครั้ง เหมืองถูกตั้งค่าเป็น 30 นาที softexpนี้ต้องมากกว่าค่าของ

เมื่อแอปฝั่งไคลเอ็นต์ของฉันส่งการร้องขอไปยังเซิร์ฟเวอร์ API (ที่ต้องใช้โทเค็นเช่นหน้ารายการลูกค้า) เซิร์ฟเวอร์จะตรวจสอบว่าโทเค็นที่ส่งนั้นยังใช้งานได้หรือไม่ตามค่าการหมดอายุดั้งเดิม ( expiresIn) หากไม่ถูกต้องเซิร์ฟเวอร์จะตอบกลับด้วยสถานะเฉพาะสำหรับข้อผิดพลาดนี้เช่น INVALID_TOKEN.

หากโทเค็นยังคงถูกต้องตามexpiredInค่า แต่มันเกินsoftexpค่าแล้วเซิร์ฟเวอร์จะตอบกลับด้วยสถานะแยกต่างหากสำหรับข้อผิดพลาดนี้เช่น EXPIRED_TOKEN:

(Math.floor(Date.now() / 1000) > decoded.softexp)

ในฝั่งไคลเอ็นต์หากได้รับEXPIRED_TOKENการตอบกลับก็ควรต่ออายุโทเค็นโดยอัตโนมัติโดยส่งคำขอต่ออายุไปยังเซิร์ฟเวอร์ สิ่งนี้โปร่งใสสำหรับผู้ใช้และจะดูแลแอพไคลเอ็นต์โดยอัตโนมัติ

วิธีการต่ออายุในเซิร์ฟเวอร์ต้องตรวจสอบว่าโทเค็นยังคงถูกต้อง:

jwt.verify(token, secret, (err, decoded) => {})

เซิร์ฟเวอร์จะปฏิเสธที่จะต่ออายุโทเค็นหากไม่สามารถใช้วิธีการข้างต้นได้


กลยุทธ์นี้ดูดี แต่ฉันคิดว่าควรได้รับการเสริมด้วย "จำนวนสูงสุดของการต่ออายุ" เพราะ (อาจ) ผู้ใช้sessiónสามารถมีชีวิตอยู่ตลอดไป
Juan Ignacio Barisich

1
คุณสามารถตั้งค่าตัวแปร hardExp ในข้อมูลโทเค็นเพื่อตั้งค่าวันที่สูงสุดเพื่อบังคับให้โทเค็นหมดอายุหรืออาจเป็นตัวนับที่จะลดลงเมื่อใดก็ตามที่มีการต่ออายุโทเค็น จำกัด จำนวนโทเค็นต่ออายุทั้งหมด
James A

1
ถูกต้อง. ฉันคิดว่านี่เป็น "ต้อง"
Juan Ignacio Barisich

2

วิธีการเกี่ยวกับวิธีนี้:

  • สำหรับคำขอของลูกค้าทุกครั้งเซิร์ฟเวอร์จะเปรียบเทียบ expirationTime ของโทเค็นด้วย (currentTime - lastAccessTime)
  • ถ้าexpirationTime <(currentTime - lastAccessedTime)จะเปลี่ยน lastAccessedTime ล่าสุดเป็น currentTime
  • ในกรณีที่ไม่มีการใช้งานบนเบราว์เซอร์ในช่วงเวลาที่เกิน expirationTime หรือในกรณีที่หน้าต่างเบราว์เซอร์ถูกปิดและexpirationTime> (currentTime - lastAccessedTime)แล้วเซิร์ฟเวอร์จะหมดอายุโทเค็นและขอให้ผู้ใช้เข้าสู่ระบบอีกครั้ง

เราไม่ต้องการจุดสิ้นสุดเพิ่มเติมสำหรับการรีเฟรชโทเค็นในกรณีนี้ จะขอบคุณ feedack ใด ๆ


มันเป็นตัวเลือกที่ดีในวันนี้มันดูง่ายสำหรับการติดตั้ง
b.ben

4
ในกรณีนี้คุณเก็บครั้งสุดท้ายที่ไหน AccessTime คุณต้องทำกับแบ็กเอนด์และตามคำขอดังนั้นมันจึงกลายเป็นทางออกที่ไม่ต้องการ
antgar9

2

ทุกวันนี้ผู้คนจำนวนมากเลือกที่จะทำการจัดการเซสชั่นกับ JWT โดยไม่ได้ตระหนักถึงสิ่งที่พวกเขายอมแพ้เพื่อให้เห็นถึงความเรียบง่าย คำตอบของฉันจะอธิบายในส่วนที่ 2 ของคำถาม:

แล้วประโยชน์ที่แท้จริงคืออะไร? ทำไมไม่มีโทเค็นเดียวเท่านั้น (ไม่ใช่ JWT) และเก็บการหมดอายุไว้บนเซิร์ฟเวอร์

มีตัวเลือกอื่น ๆ อีกไหม? การใช้ JWT ไม่เหมาะกับสถานการณ์นี้หรือไม่?

JWT มีความสามารถในการสนับสนุนการจัดการเซสชันพื้นฐานด้วยข้อ จำกัด บางอย่าง ด้วยการอธิบายโทเค็นด้วยตนเองพวกเขาไม่ต้องการสถานะใด ๆ บนฝั่งเซิร์ฟเวอร์ สิ่งนี้ทำให้พวกเขาน่าสนใจ ตัวอย่างเช่นหากบริการไม่มีเลเยอร์คงอยู่ก็ไม่จำเป็นต้องนำมาใช้ในการจัดการเซสชัน

อย่างไรก็ตามการไร้สัญชาติก็เป็นสาเหตุหลักของข้อบกพร่องเช่นกัน เนื่องจากจะมีการออกเพียงครั้งเดียวที่มีเนื้อหาคงที่และหมดอายุคุณจึงไม่สามารถทำสิ่งที่คุณต้องการด้วยการตั้งค่าการจัดการเซสชันทั่วไป

กล่าวคือคุณไม่สามารถยกเลิกการใช้งานได้ตามความต้องการ ซึ่งหมายความว่าคุณไม่สามารถใช้การล็อกเอาต์ที่ปลอดภัยเนื่องจากไม่มีวิธีหมดอายุโทเค็นที่ออกให้แล้ว คุณไม่สามารถใช้การหมดเวลาที่ไม่ได้ใช้งานด้วยเหตุผลเดียวกัน ทางออกหนึ่งคือการรักษาบัญชีดำ แต่แนะนำสถานะ

ฉันเขียนโพสต์เพื่ออธิบายข้อเสียเหล่านี้ในรายละเอียดเพิ่มเติม เพื่อความชัดเจนคุณสามารถแก้ไขสิ่งเหล่านี้ได้โดยการเพิ่มความซับซ้อนมากขึ้น (เซสชันเลื่อน, รีเฟรชโทเค็น ฯลฯ )

สำหรับตัวเลือกอื่น ๆ หากลูกค้าของคุณโต้ตอบกับบริการของคุณผ่านเบราว์เซอร์ฉันขอแนะนำให้ใช้โซลูชันการจัดการเซสชันที่อิงกับคุกกี้ ฉันยังรวบรวมวิธีการรับรองความถูกต้องของรายการที่ใช้กันอย่างแพร่หลายในเว็บในปัจจุบัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.