พื้นฐานความปลอดภัยของสปริงส์
ในบทความก่อนหน้านี้ "การใช้งานขั้นพื้นฐานของ Springboot + Spring Security และการกำหนดค่าการเข้าสู่ระบบส่วนบุคคล" ได้มีการแนะนำ Springsecurity สั้น ๆ โดยทั่วไปแนะนำอินเทอร์เฟซและใช้ฟังก์ชั่น บทความนี้พยายามทำการวิเคราะห์อย่างง่าย ๆ ของกระบวนการตรวจสอบผู้ใช้จากมุมมองของซอร์สโค้ด
ก่อนการวิเคราะห์เฉพาะเราสามารถดูหลักการทั่วไปของ Springsecurity:
พื้นฐานความปลอดภัยของสปริงส์
ในความเป็นจริงมันค่อนข้างง่ายส่วนใหญ่ผ่านชุดของตัวกรองเพื่อสกัดกั้นและประมวลผลคำขอ
คำอธิบายกระบวนการประมวลผลการรับรอง
ลองดูคลาส UsernamePasswordAuthenticationFilter โดยตรง
ระดับสาธารณะ USERNAMEPASSWORDAUTHENTICATIONFILTER ขยาย AbstractauthenticationProcessingFilter // เข้าสู่ระบบเพื่อขอการตรวจสอบความถูกต้องของการตรวจสอบความถูกต้องของประชาชนพยายาม (httpservletrequest Request, httpservletResponse) {โยน AuthenticationserviceException ใหม่ ("ไม่รองรับวิธีการตรวจสอบสิทธิ์:" + request.getMethod ()); } else {// รับผู้ใช้ชื่อผู้ใช้สตริงรหัสผ่าน = this.obtainuserName (คำขอ); สตริงรหัสผ่าน = this.obtainPassword (คำขอ); if (ชื่อผู้ใช้ == null) {username = ""; } if (รหัสผ่าน == null) {password = ""; } username = username.trim (); // สร้างโทเค็น, UserNamePassWordAticationToken AuthRequest = ใหม่ USERNAMEPASSWORDAUTHENTICATIONTOKEN (ชื่อผู้ใช้รหัสผ่าน); this.setDetails (คำขอ AuthRequest); // ตรวจสอบเพิ่มเติมส่งคืน this.getauthenticationManager (). Authenticate (AuthRequest); - ในวิธี attemptAuthentication สิ่งสำคัญคือสิ่งสำคัญคือการได้รับค่าผู้ใช้และการร้องขอรหัสผ่านจากนั้นสร้างวัตถุผู้ใช้คำว่าคำสั่งการทัศนคติสำหรับการตรวจสอบเพิ่มเติม
แต่ก่อนอื่นเราสามารถดูวิธีการก่อสร้างของ UsernamepasswordauthenticationToken
ผู้ใช้สาธารณะ WorderauthenticationToken (วัตถุหลัก, ข้อมูลรับรองวัตถุ) {// ตั้งค่าการอนุญาตว่างเปล่า super ((คอลเลกชัน) null); this.principal = principal; this.credentials = ข้อมูลรับรอง; // ตั้งค่าว่า this.setauthenticated (false);} ในความเป็นจริง UserNamePasswordAtionTicationToken ได้รับการสืบทอดมาจาก Authentication วัตถุนี้ถูกกล่าวถึงในบทความก่อนหน้า มันเป็นพารามิเตอร์ในวิธีการโทรกลับเข้าสู่ระบบที่ประสบความสำเร็จซึ่งมีพารามิเตอร์เช่นข้อมูลผู้ใช้ข้อมูลคำขอ ฯลฯ
มาดูกัน
this.getAuthenticationManager (). Authenticate (AuthRequest);
มี AuthenticationManager อยู่ที่นี่ แต่การโทรที่แท้จริงคือ ProviderManager
Public Class ProviderManager ใช้ AuthenticationManager, MessagesOrceAwe, การเริ่มต้นเบียน {การรับรองความถูกต้องของการตรวจสอบความถูกต้องสาธารณะ ขยายการรับรองความถูกต้อง> totest = Authentication.getClass (); AuthenticationException LastException = NULL; ผลการตรวจสอบความถูกต้อง = null; บูลีนดีบัก = logger.isdebugenabled (); iterator var6 = this.getProviders (). iterator (); ในขณะที่ (var6.hasnext ()) {AuthenticationProvider Provider = (AuthenticationProvider) var6.next (); // 1. พิจารณาว่ามีผู้ให้บริการเพื่อสนับสนุนการตรวจสอบสิทธิ์หรือไม่หาก (Provider.Supports (totest)) {// 2. ผลการตัดสินเชิงตรรกะที่แท้จริง = ผู้ให้บริการ. Authenticate (การรับรองความถูกต้อง); - การรับรองความถูกต้องของการตรวจสอบความถูกต้องสาธารณะ (การรับรองความถูกต้องของการรับรองความถูกต้อง) พ่น AuthenticationException {UserDetails user = this.usercache.getUserFromCache (ชื่อผู้ใช้); if (user == null) {cachewasused = false; // 1. ไปที่ userDetails user = this.RetrieveUser (ชื่อผู้ใช้, (USERNAMEPASSWORDAUTHENTICATIONTOKEN) การรับรองความถูกต้อง); } ลอง {// 2. ตรวจสอบก่อนสิ่งนี้ preauthenticationchecks.check (ผู้ใช้); // 3. ตรวจสอบเพิ่มเติม (ตรวจสอบรหัสผ่าน) this.additionalauthenticationChecks (ผู้ใช้, (USERNAMEPASSWORDAUTHENTICATIONTOKEN) การรับรองความถูกต้อง); } catch (AuthenticationException var7) {} // 4. การตรวจสอบครั้งสุดท้ายสิ่งนี้ postauthenticationchecks.check (ผู้ใช้); // 5. ส่งคืนการรับรองความถูกต้องที่ผ่านการรับรองจริงกลับมาสร้างสิ่งนี้สร้างความสำเร็จ (PrincipalToreturn, การรับรองความถูกต้อง, ผู้ใช้);} การตรวจสอบทั้งสองของผู้ใช้ที่นี่ส่วนใหญ่ผ่านสี่วิธีที่ส่งคืนประเภทบูลีน
หลังจากการตรวจสอบข้อมูลการรับรองความถูกต้องที่ได้รับการรับรองความถูกต้องจะถูกส่งกลับผ่านวิธีการก่อสร้างของ UsernamePasswordAuthenticationToken
หลังจากได้รับการรับรองความถูกต้องที่ผ่านการรับรองแล้ว SuccessHandler จะถูกเรียกอีกครั้ง หรือหากไม่สามารถตรวจสอบความถูกต้องให้โทรล้มเหลว
วิธีการแบ่งปันผลลัพธ์การรับรองความถูกต้องระหว่างการร้องขอหลายครั้ง
หลังจากเสร็จสิ้นกระบวนการประมวลผลการรับรองความถูกต้องของผู้ใช้ลองคิดดูวิธีแบ่งปันผลการตรวจสอบความถูกต้องระหว่างคำขอหลายรายการ
เนื่องจากไม่มีการกำหนดค่าสำหรับสิ่งนี้เราจึงสามารถนึกถึงวิธีการเริ่มต้นที่ควรจัดเก็บผลลัพธ์การรับรองความถูกต้องในเซสชัน
แล้วมันจะถูกเก็บไว้ในเซสชั่นเมื่อใด
เราสามารถดูซอร์สโค้ดของกระบวนการตรวจสอบความถูกต้องต่อไป หลังจากผ่านวิธีการทดสอบความพยายามหากการตรวจสอบความถูกต้องประสบความสำเร็จจะมีการเรียกร้องให้ประสบความสำเร็จ ในวิธีนี้ไม่เพียง แต่เรียกว่า SuccessHandler เท่านั้น แต่ยังรวมถึงบรรทัดของรหัสที่สำคัญกว่า
SecurityContextholder.getContext (). setauthentication (Authresult);
SecurityContextholder เป็นแพ็คเกจสำหรับ ThreadLocal Threadlocal เป็นคลาสที่เก็บข้อมูลภายในเธรด ข้อมูลสามารถเก็บไว้ในเธรดที่ระบุ หลังจากการจัดเก็บข้อมูลเฉพาะข้อมูลที่เก็บไว้สามารถรับได้ในเธรดที่ระบุ แต่เธรดอื่นไม่สามารถรับข้อมูลได้ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับหลักการของ ThreadLocal โปรดตรวจสอบบทความก่อนหน้าของฉัน
โดยทั่วไปการร้องขอและการส่งคืนอินเทอร์เฟซเดียวกันจะเสร็จสมบูรณ์ในเธรดเดียว เราใส่ Authresult ใน SecurityContextholder และเรายังสามารถนำมันออกมาได้ทุกที่
ในที่สุด Authresult จะถูกดึงมาจาก SecurityContextPersistenceFilter และเซสชันจะถูกเก็บไว้
SecurityContextPersistenceFilter ยังเป็นตัวกรองซึ่งอยู่ในระดับแนวหน้าของห่วงโซ่ตัวกรองความปลอดภัยทั้งหมดซึ่งหมายความว่าตัวกรองจะถูกส่งผ่านครั้งแรกเมื่อเริ่มการตรวจสอบและผ่านสุดท้ายผ่านหลังจากการตรวจสอบเสร็จสิ้น
รับข้อมูลผู้ใช้ที่ได้รับการรับรองความถูกต้อง
/*** รับผู้ใช้ที่เข้าสู่ระบบในปัจจุบัน* @return การรับรองความถูกต้องที่สมบูรณ์*/ @getMapping ("/me1") วัตถุสาธารณะ currentUser () {ส่งคืนความปลอดภัย contextholder.getContext (). getauthentication ();} @getMapping ("/me2") UserDetails */@getMapping ("/me3") วัตถุสาธารณะ cuurentuser (@authenticationprincipal ผู้ใช้งานผู้ใช้งานผู้ใช้งาน) {return userdetails;}ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น