คำนำ
กรอบการอนุญาตทั่วไปที่ได้รับความนิยมในขณะนี้รวมถึง Shiro of Apache และ Spring Family Spring Security เมื่อพูดถึงการรับรองความถูกต้องของ Microservice ในปัจจุบันเราจำเป็นต้องใช้กรอบการอนุญาตของเราเพื่อสร้างบริการตรวจสอบความถูกต้องของเราเอง วันนี้นายกรัฐมนตรีเป็นนายกรัฐมนตรี
การรักษาความปลอดภัยในสปริงส่วนใหญ่ใช้การรับรองความถูกต้อง (การตรวจสอบสิทธิ์วิธีแก้ปัญหาคุณเป็นใคร?) และการควบคุมการเข้าถึง (การควบคุมการเข้าถึงนั่นคือคุณได้รับอนุญาตให้ทำอะไร? หรือที่เรียกว่าการอนุญาต) Spring Security แยกการรับรองความถูกต้องจากสถาปัตยกรรมการอนุญาตและให้คะแนนส่วนขยาย
วัตถุหลัก
รหัสหลักอยู่ภายใต้แพ็คเกจสปริงที่มีความปลอดภัย-คอร์ เพื่อให้เข้าใจถึงความปลอดภัยของฤดูใบไม้ผลิคุณต้องใส่ใจกับวัตถุหลักภายใน
SecurityContextholder, SecurityContext และการตรวจสอบสิทธิ์
SecurityContextholder เป็นคอนเทนเนอร์ที่เก็บข้อมูลสำหรับ SecurityContext การจัดเก็บ ThreadLocal ถูกใช้โดยค่าเริ่มต้นซึ่งหมายความว่าวิธีการรักษาความปลอดภัยจะมีอยู่ในเธรดเดียวกัน
SecurityContext ส่วนใหญ่จัดเก็บข้อมูลหลักของแอปพลิเคชันและแสดงโดยการรับรองความถูกต้องใน Spring Security
รับเงินต้น:
Principal Object = SecurityContextholder.getContext (). getAuthentication (). getPrincipal (); ถ้า (principal instanceof userDetails) {string username = ((userDetails) principal) .getUserName ();ใน Spring Security คุณสามารถดูคำจำกัดความการตรวจสอบความถูกต้อง:
การรับรองความถูกต้องของอินเทอร์เฟซสาธารณะขยายเงินต้น {คอลเลกชัน {คอลเลกชัน <? ขยาย Grantedauthority> getAuthorities (); / *** โดยปกติรหัสผ่าน*/ วัตถุ getCredentials (); /*** จัดเก็บรายละเอียดเพิ่มเติมเกี่ยวกับคำขอตรวจสอบความถูกต้อง สิ่งเหล่านี้อาจเป็นที่อยู่ IP * หมายเลขซีเรียลใบรับรอง ฯลฯ */ วัตถุ getDetails (); /*** ใช้เพื่อระบุว่ามีการรับรองความถูกต้องหรือไม่ หากคุณเข้าสู่ระบบด้วยชื่อผู้ใช้และรหัสผ่านมักจะเป็นชื่อผู้ใช้*/ Object getPrincipal (); / *** ไม่ว่าจะเป็นการรับรองความถูกต้อง*/ บูลีน isauthenticated (); เป็นโมฆะ setauthenticated (boolean isauthenticated) พ่น unledalargumentexception;}ในการใช้งานจริงมักใช้ UserNamePasswordaThenticationToken:
บทคัดย่อระดับสาธารณะ AbstractauthenticationToken ใช้การตรวจสอบความถูกต้อง, credentialScontainer {} ระดับสาธารณะ USERNAMEPASSWORDATHENTICATIONTOKEN ขยาย AbstractauthenticationToken {}กระบวนการตรวจสอบความถูกต้องร่วมกันมักจะเป็นเช่นนี้: สร้าง UsernamePasswordaThenticationToken จากนั้นส่งมอบให้กับ AuthenticationManager สำหรับการตรวจสอบ (อธิบายในรายละเอียดในภายหลัง) หากผ่านการตรวจสอบความถูกต้องข้อมูลการตรวจสอบจะถูกเก็บไว้ผ่าน SecurityContextholder
USERNAMEPASSWORDAUTHENTICATIONTOKEN AUTHENTICATIONTOKEN = ใหม่ USERNAMEPASSWORDAUTHENTICATIONTOKEN (LOGINVM.GETUSERNAME (), LOGINVM.GETPASSWORD ()); การรับรองความถูกต้องของการรับรองความถูกต้อง = this.AuthenticationManager.Authenticate (AuthenticationToken);
ผู้ใช้งานและผู้ใช้งาน Service
UserDetails เป็นอินเทอร์เฟซสำคัญใน Spring Security ซึ่งใช้เพื่อเป็นตัวแทนของเงินต้น
ผู้ใช้ส่วนต่อประสานสาธารณะช่วยขยายข้อมูล { / *** ข้อมูลการอนุญาตผู้ใช้สามารถเข้าใจได้ว่าเป็นบทบาท* / คอลเลกชัน <? ขยาย Grantedauthority> getAuthorities (); / ** * รหัสผ่านผู้ใช้ * * @@Retern รหัสผ่าน */ String getPassword (); / *** ชื่อผู้ใช้**/ สตริง getUserName (); บูลีน isaccountnonexpired (); บูลีน isaccountnonlocked (); บูลีน iscredentialsentsnonexpired (); บูลีน isenabled ();}ผู้ใช้งานให้ข้อมูลที่จำเป็นสำหรับการตรวจสอบความถูกต้อง ในการใช้งานจริงคุณสามารถใช้งานผู้ใช้ด้วยตัวเองและเพิ่มข้อมูลเพิ่มเติมเช่นอีเมลมือถือและข้อมูลอื่น ๆ
ในการรับรองความถูกต้องอาจารย์ใหญ่มักจะเป็นชื่อผู้ใช้ เราสามารถรับผู้ใช้รายละเอียดผ่านเงินต้นผ่าน UserDetailsService:
Public Interface UserDetailsService {userDetails loadUserByUserName (ชื่อผู้ใช้สตริง) โยน UserNamEnotFoundException;}การให้สิทธิ์
ดังที่ได้กล่าวไว้ในผู้ใช้รายละเอียดการได้รับสิทธิ์สามารถเข้าใจได้ว่าเป็นบทบาทเช่น Role_administrator หรือ Role_hr_supervisor
สรุป
การรับรองการรับรองความถูกต้อง
AuthenticationManager
การรับรองความถูกต้องส่วนใหญ่ทำได้ผ่านส่วนต่อประสาน AuthenticationManager ซึ่งมีเพียงวิธีเดียวเท่านั้น:
ส่วนต่อประสานสาธารณะ AuthenticationManager {การรับรองความถูกต้องการรับรองความถูกต้อง (การรับรองความถูกต้องของการรับรองความถูกต้อง) พ่น AuthenticationException;}วิธีการรับรองความถูกต้อง () ส่วนใหญ่ทำสามสิ่ง:
AuthenticationException เป็นข้อยกเว้นรันไทม์ซึ่งมักจะจัดการโดยแอปพลิเคชันในลักษณะทั่วไป รหัสผู้ใช้มักไม่จำเป็นต้องถูกจับและประมวลผลโดยเฉพาะ
การใช้งานเริ่มต้นของ AuthenticationManager คือ ProviderManager ซึ่งมอบหมายชุดของอินสแตนซ์ AuthenticationProvider เพื่อใช้การรับรองความถูกต้อง
AuthenticationProvider และ AuthenticationManager นั้นคล้ายกับการรับรองความถูกต้องทั้งสองมีการรับรองความถูกต้อง แต่มีวิธีการเพิ่มเติมเพื่อการสอบถามว่าผู้โทรรองรับประเภทการรับรองความถูกต้องหรือไม่:
การรับรองความถูกต้องของอินเทอร์เฟซ บูลีนรองรับ (คลาส <?> การตรวจสอบ);}
ProviderManager มีชุดของ AuthenticationProviders เมื่อดำเนินการรับรองความถูกต้องมันจะผ่านผู้ให้บริการแล้วโทรหาฝ่ายสนับสนุน หากได้รับการสนับสนุนจะดำเนินการวิธีการรับรองความถูกต้องที่ข้ามผู้ให้บริการปัจจุบัน หากผู้ให้บริการได้รับการรับรองความถูกต้องให้แตกหัก
การรับรองความถูกต้องของการรับรองความถูกต้องสาธารณะ (การรับรองความถูกต้องของการรับรองความถูกต้อง) พ่น AuthenticationException {class <? ขยายการรับรองความถูกต้อง> totest = Authentication.getClass (); AuthenticationException LastException = NULL; ผลการตรวจสอบความถูกต้อง = null; บูลีนดีบัก = logger.isdebugenabled (); สำหรับ (AuthenticationProvider Provider: getProviders ()) {ถ้า (! provider.supports (totest)) {ดำเนินการต่อ; } if (debug) {logger.debug ("พยายามตรวจสอบความถูกต้องโดยใช้" + provider.getClass (). getName ()); } ลอง {result = provider.authenticate (การรับรองความถูกต้อง); if (result! = null) {copyDetails (การรับรองความถูกต้องผลลัพธ์); หยุดพัก; }} catch (accountstatusexception e) {prepereException (e, การตรวจสอบ); // sec-546: หลีกเลี่ยงการสำรวจผู้ให้บริการเพิ่มเติมหากความล้มเหลวของการตรวจสอบความถูกต้องเกิดจาก // สถานะบัญชีที่ไม่ถูกต้องโยน e; } catch (internalauthenticationserviceException e) {prepereException (e, การพิสูจน์ตัวตน); โยน e; } catch (AuthenticationException e) {lastException = e; }} if (result == null && parent! = null) {// อนุญาตให้ผู้ปกครองลอง ลอง {result = parent.authenticate (การรับรองความถูกต้อง); } catch (providerNotFoundException e) {// ละเว้นในขณะที่เราจะโยนไปด้านล่างหากไม่มีข้อยกเว้นอื่น ๆ เกิดขึ้นก่อน // การเรียกผู้ปกครองและผู้ปกครอง // อาจโยน providernotfound แม้ว่าผู้ให้บริการในเด็กอยู่แล้ว // จัดการคำขอ} catch (AuthenticationException e) }} if (ผลลัพธ์! = null) {ถ้า (erasecredentialsafterauthentication && (อินสแตนซ์ผลลัพธ์ของ credentialScontainer)) {// การรับรองความถูกต้องเสร็จสมบูรณ์ ลบข้อมูลรับรองและข้อมูลลับอื่น ๆ // จากการตรวจสอบ ((credentialScontainer) ผลลัพธ์) .erasecredentials (); } EventPublisher.publishauthenticationsuccess (ผลลัพธ์); ผลการกลับมา; } // พาเรนต์เป็นโมฆะหรือไม่ได้ตรวจสอบ (หรือโยนข้อยกเว้น) if (lastException == null) {lastException = ใหม่ providerNotFoundException (messages.getMessage ("ProviderManager.providerNotFound", วัตถุใหม่ [] {totest.getName ()}, "ไม่พบการรับรองความถูกต้อง } PrepereException (LastException, Authentication); โยน Lastexception; -ดังที่เห็นได้จากรหัสข้างต้น ProviderManager มีผู้ปกครองที่เป็นตัวเลือก หากผู้ปกครองไม่ว่าง
AuthenticationProvider
AuthenticationProvider มีการใช้งานมากมาย สิ่งที่คุณกังวลมากที่สุดคือ DaoauthenticationProvider ที่สืบทอดมาจาก AbstractUserDetailsauthenticationProvider หลักคือการใช้การรับรองความถูกต้องผ่านทางผู้ใช้ DaoauthenticationProvider จะถูกโหลดโดยอัตโนมัติโดยอัตโนมัติและไม่จำเป็นต้องกำหนดค่าด้วยตนเอง
ก่อนอื่นให้ดูที่ AbstractUserDetailsauthenticationProvider และดูการรับรองความถูกต้องหลักที่สุด:
การรับรองความถูกต้องของการตรวจสอบความถูกต้องสาธารณะ (การรับรองความถูกต้องของการรับรองความถูกต้อง) พ่นการรับรองความถูกต้อง Exception {// ต้องเป็นผู้ใช้งานคำว่าคำสั่ง assert.isinstanceof (USERNAMEPASSWORDAUTHENTICATIONTOKEN.CLASS, Authentication, Messages.GetMessage ( สนับสนุน ")); // รับชื่อผู้ใช้ชื่อผู้ใช้ชื่อผู้ใช้ = (Authentication.getPrincipal () == null)? "None_Provided": Authentication.getName (); บูลีน cachewasused = true; // รับผู้ใช้จาก Cache user = this.usercache.getUserFromCache (ชื่อผู้ใช้); if (user == null) {cachewasused = false; ลอง {// Retrieveuser Abstract Method เพื่อให้ผู้ใช้ผู้ใช้ = RetrieveUser (ชื่อผู้ใช้, (USERNAMEPASSWORDAUTHENTICATIONTOKEN) การรับรองความถูกต้อง); } catch (userNamenotFoundException notfound) {logger.debug ("ผู้ใช้" "ชื่อผู้ใช้ +" 'ไม่พบ "); if (hideusernotfoundexceptions) {โยน badcredentialsexception ใหม่ (messages.getMessage ("AbstractUserDetailsauthenticationProvider.badCredentials", "Bad Credentialss")); } else {โยน notfound; }} assert.notNull (ผู้ใช้, "RetrieveUser ส่งคืน NULL - การละเมิดสัญญาอินเตอร์เฟส"); } ลอง {// pre-check, defaultpreauthenticationChecks ตรวจสอบว่าผู้ใช้ถูกล็อคหรือไม่หรือบัญชีนั้นพร้อมใช้งานสำหรับ preauthenticationChecks.check (ผู้ใช้); // วิธีการบทคัดย่อ, ตรวจสอบการตรวจสอบเพิ่มเติมเพิ่มเติมที่กำหนดเอง } catch (ข้อยกเว้น AuthenticationException) {ถ้า (cachewasused) {// มีปัญหาดังนั้นลองอีกครั้งหลังจากตรวจสอบ // เรากำลังใช้ข้อมูลล่าสุด (เช่นไม่ได้มาจากแคช) cachewasused = false; user = retrieveUser (ชื่อผู้ใช้, (USERNAMEPASSWORDAUTHENTICATIONTOKEN) การตรวจสอบ); preauthenticationchecks.Check (ผู้ใช้); เพิ่มเติม AuthenticationChecks (ผู้ใช้, (USERNAMEPASSWORDAUTHENTICATIONTOKEN) การรับรองความถูกต้อง); } else {โยนข้อยกเว้น; }} // post-check defaultpostauthenticationChecks ตรวจสอบ isCredentialSnonexpired postauthenticationChecks.Check (ผู้ใช้); if (! cachewasused) {this.usercache.putuserincache (ผู้ใช้); } Object PrincipalToreturn = ผู้ใช้; if (forcePrincipalASString) {principalToreturn = user.getUserName (); } return createsuccessauthentication (principalToreturn, การตรวจสอบ, ผู้ใช้); -การทดสอบข้างต้นส่วนใหญ่ขึ้นอยู่กับการใช้งานผู้ใช้งานที่มีการใช้งานซึ่งผู้ใช้ได้รับและตรรกะการตรวจสอบจะถูกนำไปใช้โดยคลาสที่เฉพาะเจาะจง การใช้งานเริ่มต้นคือ daoauthenticationprovider แกนหลักของคลาสนี้คือการอนุญาตให้นักพัฒนาให้ผู้ใช้งาน Service เพื่อรับผู้ใช้และรหัสผ่านเพื่อตรวจสอบว่ารหัสผ่านนั้นถูกต้องหรือไม่:
UserDetailsService Private UserDetailsService; รหัสผ่านส่วนตัวรหัสผ่านรหัสผ่าน;
หากต้องการดูการใช้งานที่เฉพาะเจาะจง RetrieveUser โทรหาผู้ใช้งานโดยตรงเพื่อรับผู้ใช้:
ได้รับการป้องกันขั้นสุดท้าย UserDetails RetrieveUser (String username, UserNamePasswordAuthenticationToken Authentication) พ่น AuthenticationException {UserDetails loadeduser; ลอง {loadedUser = this.getUserDetailsService (). loaduserByUserName (ชื่อผู้ใช้); } catch (userNamenotFoundException notfound) {ถ้า (Authentication.getCredentials ()! = null) {สตริงนำเสนอ password = Authentication.getCredentials (). toString (); PasswordEncoder.ispasswordValid (USERNOTFOUNDENCODEDEDPASSWORD, PRENTEDPASSWORD, NULL); } โยนไม่ตาย; } catch (ข้อยกเว้น repositoryproblem) {โยน InternalauthenticationserviceException ใหม่ (repositoryproblem.getMessage (), RepositoryProblem); } if (loadedUser == null) {โยน InternalauthenticationserviceException ใหม่ ("UserDetailsService ส่งคืน NULL ซึ่งเป็นการละเมิดสัญญาอินเทอร์เฟซ"); } return loadeduser; -มาดูการยืนยัน:
เป็นโมฆะที่ได้รับการป้องกันเพิ่มเติม AuthenticationChecks (ผู้ใช้งานผู้ใช้งานผู้ใช้, UserNamePasswordAuthenticationToken Authentication) พ่น AuthenticationException {Object Salt = NULL; if (this.saltsource! = null) {salt = this.saltsource.getSalt (userDetails); } if (Authentication.getCredentials () == null) {logger.debug ("การรับรองความถูกต้องล้มเหลว: ไม่มีข้อมูลรับรอง"); โยน badcredentialsexception ใหม่ (messages.getMessage ("AbstractUserDetailsauthenticationProvider.BadCredentials", "Bad Credentialss")); } // รับสตริงรหัสผ่านผู้ใช้ที่นำเสนอ password = uthentication.getCredentials (). toString (); // เปรียบเทียบว่ารหัสผ่านหลังจากรหัสผ่านของรหัสผ่านนั้นเหมือนกับรหัสผ่านของผู้ใช้เครื่องยนต์หรือไม่หาก (! PasswordEncoder.ispasswordValid (userDetails.getPassword (), password, salt)) {logger.debug ("การรับรองความถูกต้อง: รหัสผ่านไม่ตรงกับค่าที่เก็บไว้"); โยน badcredentialsexception ใหม่ (messages.getMessage ("AbstractUserDetailsauthenticationProvider.BadCredentials", "Bad Credentialss")); -สรุป: ในการปรับแต่งการรับรองความถูกต้องให้ใช้ daoauthenticationProvider คุณจะต้องจัดเตรียมรหัสผ่านและผู้ใช้งาน
ปรับแต่งผู้จัดการการรับรองความถูกต้อง
SPRING Security ให้ AuthenticationManagerBuilder ซึ่งช่วยให้คุณสามารถใช้การรับรองความถูกต้องที่กำหนดเองได้อย่างรวดเร็ว
ดูคำอธิบายซอร์สโค้ดอย่างเป็นทางการ:
SecurityBuilder ใช้ในการสร้าง AuthenticationManager ช่วยให้สามารถสร้างการรับรองความถูกต้องของหน่วยความจำได้อย่างง่ายดายการตรวจสอบ LDAP การรับรองความถูกต้องตาม JDBC เพิ่ม UserDetailsService และเพิ่ม AuthenticationProvider's
AuthenticationManagerBuilder สามารถใช้ในการสร้าง AuthenticationManager ซึ่งสามารถสร้างการรับรองความถูกต้องตามหน่วยความจำการตรวจสอบ LDAP การตรวจสอบความถูกต้องของ JDBC และเพิ่ม UserDetailsService และ AuthenticationProvider
ใช้ง่าย:
@การกำหนดค่า@enableWebsecurity@enableGlobalMethodSecurity (prepostenabled = true, secureDenabled = true) แอปพลิเคชันระดับสาธารณะความปลอดภัยขยาย WebSecurityConfigurerAdapter {Public SecurityConfiguration Corsfilter, SecurityProblemsupport ปัญหา Upport) {this.AuthenticationManagerBuilder = AuthenticationManagerBuilder; this.userDetailsService = userDetailSService; this.tokenprovider = tokenprovider; this.corsfilter = corsfilter; this.problemsupport = ปัญหาสนับสนุน; } @PostConstruct โมฆะสาธารณะ init () {ลอง {AuthenticationManagerBuilder .USERDETAILSSERVICE (USERDETAILSSERVICE) .PasswordEncoder (PasswordEncoder ()); } catch (Exception e) {โยน beaninitializationException ใหม่ ("การกำหนดค่าความปลอดภัยล้มเหลว", e); }} @Override void protected กำหนดค่า (httpsecurity http) โยนข้อยกเว้น {http .addfilterbefore (corsfilter, usernamepasswordauthenticationfilter.class) .headers () .FrameOptions () .Disable (). และ () .SessionManagement () .sessionCreationPolicy (SessionCreationPolicy.Stateless). และ () .AuthorizeRequests () .AntMatchers ("/API/register") .AntMatchers ("/API/Authenticate"). permitall () .AntMatchers ("/api/account/reset-password/init"). permitall () .AntMatchers ("/api/account/reset-password/finish"). .AntMatchers ("/api/**"). การรับรองความถูกต้อง () .AntMatchers ("/การจัดการ/สุขภาพ"). permitall () .AntMatchers ("/การจัดการ/**"). Hasauthority .AntMatchers ("/แหล่งข้อมูล/การกำหนดค่า/การกำหนดค่า/ui"). permitall () .AntMatchers ("/swagger-ui/index.html"). hasauthority (changeconstants.admin) .and () -การอนุญาตและการควบคุมการเข้าถึง
เมื่อการรับรองความถูกต้องประสบความสำเร็จเราสามารถอนุญาตต่อไปซึ่งจะดำเนินการผ่าน AccessDecisionManager มีสามการใช้งานของเฟรมเวิร์กค่าเริ่มต้นคือการยืนยันซึ่งทำผ่าน AccessDecisionVoter ซึ่งเป็นเหมือนผู้ให้บริการที่ได้รับมอบหมายให้รับรองความถูกต้องสำหรับการตรวจสอบสิทธิ์
การตัดสินใจโมฆะสาธารณะ (การรับรองความถูกต้องการรับรองความถูกต้องวัตถุวัตถุการรวบรวม <CONFINTTRIBUTE> configatTributes) พ่น AccessDeniedException {int deny = 0; // Traversal DecisionVoter สำหรับ (AccessDecisionVoter ผู้มีสิทธิเลือกตั้ง: getDecisionVoters ()) {// การลงคะแนน int result = vote.vote (การตรวจสอบ, วัตถุ, configattributes); if (logger.isdebugenabled ()) {logger.debug ("ผู้ลงคะแนน:" + ผู้มีสิทธิเลือกตั้ง + ", ส่งคืน:" + ผลลัพธ์); } switch (ผลลัพธ์) {case accessDecisionVoter.access_granted: return; Case AccessDecisionVoter.access_denied: Deny ++; หยุดพัก; ค่าเริ่มต้น: break; }} // veto if (deny> 0) {โยน accessDeniedException ใหม่ (messages.getMessage ("AbstractaccessDecisionManager.accessDenied", "การเข้าถึงถูกปฏิเสธ")); } // เพื่อให้ได้มาไกลขนาดนี้ทุก accessDecisionVoter งด checkallowLowFallAbstainDecisions (); -มาดู AccessDecisionVoter กันเถอะ:
Boolean รองรับ (แอตทริบิวต์ configattribute); Boolean รองรับ (คลาส <s?> clazz); int vote (การรับรองความถูกต้องของการรับรองความถูกต้อง, วัตถุ S, คอลเลกชัน <Configattribute> แอตทริบิวต์);
วัตถุเป็นทรัพยากรที่ผู้ใช้ต้องการเข้าถึงและ configattribute เป็นเงื่อนไขที่ต้องปฏิบัติตามวัตถุ โดยปกติแล้วน้ำหนักบรรทุกจะเป็นสตริงเช่น Role_admin ลองมาดูการใช้งาน Rolevoter แกนกลางคือการแยก Grantedauthority จากการตรวจสอบแล้วจากนั้นเปรียบเทียบกับ configattribute ว่าจะเป็นไปตามเงื่อนไขหรือไม่
บูลีนสาธารณะสนับสนุน (แอตทริบิวต์ configattribute) {if ((attribute.getAttribute ()! = null) && attribute.getAttribute (). startswith (getRolePreFix ())) {return true; } else {return false; }} บูลีนสาธารณะสนับสนุน (คลาส <?> clazz) {return true; } การโหวต INT สาธารณะ (การรับรองความถูกต้องการรับรองความถูกต้องวัตถุวัตถุ, คอลเลกชัน <COFINTTRIBUTE> แอตทริบิวต์) {ถ้า (การรับรองความถูกต้อง == null) {return access_denied; } int result = access_abstain; // รับข้อมูลที่ได้รับอนุญาตการรวบรวม <? ขยาย Grantedauthority> เจ้าหน้าที่ = Extractauthorities (การตรวจสอบ); สำหรับ (แอตทริบิวต์ configattribute: แอตทริบิวต์) {ถ้า (this.supports (แอตทริบิวต์)) {// การเข้าถึงถูกปฏิเสธโดยผลลัพธ์เริ่มต้น = access_denied; // พยายามค้นหาอำนาจที่ได้รับการจับคู่สำหรับ (Grantedauthority Authority: เจ้าหน้าที่) {// พิจารณาว่ามีอำนาจการจับคู่หรือไม่ถ้า (attribute.getAttribute (). Equals (Author.getAuthority ())) {// คุณสามารถเข้าถึง return access_granted; }}}} ผลการส่งคืน; -ที่นี่ฉันต้องถามว่า configattribute มาจากไหน? ในความเป็นจริงมันอยู่ในการกำหนดค่าของแอปพลิเคชันความปลอดภัยด้านบน
วิธีการใช้ความปลอดภัยของเว็บ
การรักษาความปลอดภัยในสปริง (สำหรับแบ็กเอนด์ UI และ HTTP) ใน Web Layer ขึ้นอยู่กับตัวกรอง servlet และรูปต่อไปนี้แสดงลำดับชั้นทั่วไปของตัวจัดการสำหรับคำขอ HTTP เดียว
Spring Security ลงทะเบียนกับ Web Layer ผ่าน FilterChainproxy เป็นตัวกรองเดียวตัวกรองภายในพร็อกซี
FilterChainproxy เทียบเท่ากับคอนเทนเนอร์ตัวกรอง ผ่าน VirtualFilterchain ตัวกรองภายในแต่ละตัวจะเรียกตามลำดับ
โมฆะสาธารณะ dofilter (คำขอ ServletRequest, การตอบสนอง servletResponse, ห่วงโซ่ FilterChain) พ่น IOException, servletexception {boolean clearContext = request.getAttribute (filter_applied) == null; if (clearContext) {ลอง {request.setAttribute (filter_applied, boolean.true); dofilterinternal (คำขอ, การตอบสนอง, โซ่); } ในที่สุด {SecurityContextholder.ClearContext (); request.removeattribute (filter_applied); }} else {dofilterInternal (คำขอ, การตอบสนอง, โซ่); }} โมฆะส่วนตัว dofilterInternal (คำขอ ServletRequest, การตอบสนอง servletResponse, ห่วงโซ่ FilterChain) พ่น IOException, Servletexception {FirewallEdRequest fwrequest = ไฟร์วอลล์ httpservletResponse fwresponse = ไฟร์วอลล์. getFireWalledResponse ((httpservletResponse) การตอบสนอง); รายการ <filter> ตัวกรอง = getFilters (fwrequest); if (ตัวกรอง == null || filters.size () == 0) {ถ้า (logger.isdebugenabled ()) {logger.debug (urlutils.buildrequesturl (fwrequest) + (ตัวกรอง == null? } fwrequest.reset (); chain.dofilter (fwrequest, fwresponse); กลับ; } VirtualFilterChain VFC = ใหม่ VirtualFilterChain (fwrequest, โซ่, ตัวกรอง); vfc.dofilter (fwrequest, fwresponse); } คลาสคงที่คลาสคงที่ VirtualFilterChain ใช้ FilterChain {ภาคเอกชนสุดท้าย FILTERCHAIN OriginalChain; รายการสุดท้ายส่วนตัว <Filter> เพิ่มเติม Filters; FirewalledRequest FirewalledRequest ส่วนตัวสุดท้าย; ขนาด int สุดท้ายส่วนตัว; private int currentPosition = 0; VirtualFilterChain ส่วนตัว (FirewalledRequest FirewalledRequest, FilterChain Chain, รายการ <filter> เพิ่มเติม Filters) {this.originalchain = chain; this.additionalFilters = เพิ่มเติม filters; this.size = motionFilters.size (); this.firewalledRequest = FirewalledRequest; } โมฆะสาธารณะ dofilter (คำขอ servletrequest, การตอบสนอง servletResponse) พ่น ioexception, servletexception {ถ้า (currentposition == ขนาด) {ถ้า (logger.isdebugenabled ()) {logger.debug (urlutils.buildrequesturl } // ปิดการใช้งาน Path Striping ในขณะที่เราออกจากห่วงโซ่ตัวกรองความปลอดภัยนี้ firewalledrequest.reset (); OriginalChain.dofilter (คำขอ, การตอบกลับ); } else {CurrentPosition ++; ตัวกรอง nextFilter = เพิ่มเติม filters.get (CurrentPosition - 1); if (logger.isdebugenabled ()) {logger.debug (urlutils.buildrequesturl (FirewalledRequest) + "ที่ตำแหน่ง" + currentposition + "ของ" + size + "ในโซ่ตัวกรองเพิ่มเติม } nextfilter.dofilter (คำขอ, การตอบกลับ, สิ่งนี้); -อ้างถึง
https://spring.io/guides/topicals/spring-security-architecture/
https://docs.spring.io/spring-security/site/docs/5.0.5.release/reference/htmlsingle/#overall-architecture
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com