ต้นทาง
ในมาตรฐาน RABC การอนุญาตต้องรองรับการกำหนดค่าแบบไดนามิกค่าเริ่มต้นความปลอดภัยของสปริงเพื่อตกลงการอนุญาตในรหัส สถานการณ์ทางธุรกิจจริงมักจะกำหนดให้มีการกำหนดค่าสิทธิ์การเข้าถึงบทบาทแบบไดนามิกนั่นคือเพื่อกำหนดค่าบทบาทการเข้าถึงที่สอดคล้องกับ URL ที่รันไทม์
ขึ้นอยู่กับความปลอดภัยของฤดูใบไม้ผลิวิธีการบรรลุข้อกำหนดนี้?
วิธีที่ง่ายที่สุดคือการปรับแต่งตัวกรองเพื่อให้การตัดสินอนุญาตเสร็จสมบูรณ์ แต่สิ่งนี้แยกออกจากกรอบความปลอดภัยของฤดูใบไม้ผลิ วิธีการใช้งานอย่างหรูหราตามความปลอดภัยของฤดูใบไม้ผลิ?
การตรวจสอบการอนุญาตการรักษาความปลอดภัยของฤดูใบไม้ผลิ
Spring Security FilterChainproxy ใช้เป็นตัวกรองเพื่อลงทะเบียนกับเว็บ FilterChainproxy มีตัวกรองในตัวหลายตัวพร้อมกัน ก่อนอื่นเราต้องเข้าใจตัวกรองต่าง ๆ ที่อยู่ใน Spring Security:
| นามแฝง | คลาสกรอง | องค์ประกอบหรือแอตทริบิวต์เนมสเปซ |
|---|---|---|
| channel_filter | channelprocessingFilter | http/intercept-url@ต้องใช้ช่องทาง |
| security_context_filter | SecurityContextPersistenceFilter | http |
| พร้อมกัน _session_filter | พร้อมกัน filter | การจัดการเซสชัน/การควบคุมพร้อมกัน |
| Headers_filter | headerWriterFilter | http/ส่วนหัว |
| csrf_filter | csrffilter | http/csrf |
| logout_filter | logoutfilter | http/logout |
| x509_filter | x509authenticationFilter | http/x509 |
| pre_auth_filter | AbstractpreauthenticatedprocessingFilter subclasses | N/A |
| cas_filter | CasauthenticationFilter | N/A |
| form_login_filter | USERNAMEPASSWORDAUTHENTICATIONFILTER | http/form-login |
| masic_auth_filter | BasicAuthenticationFilter | http/http-basic |
| servlet_api_support_filter | SecurityContextholderAwareRequestFilter | http/@servlet-api-provision |
| jaas_api_support_filter | jaasapiintegrationfilter | http/@jaas-api-provision |
| จำ _me_filter | RememberMeauthenticationFilter | http/demogle-me |
| anonymous_filter | AnonymousauthenticationFilter | http/anonymous |
| session_management_filter | SessionManagementFilter | การจัดการเซสชัน |
| exception_translation_filter | ExceptionTranslationFilter | http |
| filter_security_interceptor | FiltersecurityInterceptor | http |
| switch_user_filter | SwitchUserFilter | N/A |
สิ่งที่สำคัญที่สุดคือ FiltersecurityInterceptor ซึ่งใช้ตรรกะการรับรองความถูกต้องหลักและรหัสหลักส่วนใหญ่อยู่ที่นี่:
Protected InterceptorStatustoken ก่อนการประชุม (วัตถุวัตถุ) {// รับสิทธิ์ที่จำเป็นในการเข้าถึงการรวบรวม URL <CONFINTTRIBUTE> แอตทริบิวต์ = this.ObTainSecurityMetAdatAsource () .getAttributes (วัตถุ); การรับรองความถูกต้องรับรองความถูกต้อง = AuthenticateIfRequired (); // การรับรองความถูกต้องผ่าน AccessDecisionManager ลอง {this.accessDecisionManager.docide (การรับรองความถูกต้อง, วัตถุ, แอตทริบิวต์); } catch (AccessDeniedException AccessDeniedException) {PublisheVent (ใหม่ AuthorizationFailureEvent (วัตถุ, แอตทริบิวต์, การรับรองความถูกต้อง, AccessDeniedException)); โยน accessideniedexception; } if (debug) {logger.debug ("การอนุญาตให้สำเร็จ"); } if (publishauthorizationsuccessful ");} if (publishauthorizationsuccess) {publisheVent (ผู้ได้รับอนุญาตใหม่ (วัตถุใหม่ (วัตถุ, คุณลักษณะ, การรับรองความถูกต้อง));} // พยายามเรียกใช้เป็น runas -runasManage.buildrunas {logger.debug ("RunasManager ไม่ได้เปลี่ยนวัตถุการตรวจสอบสิทธิ์")} // ไม่มีการทำงานเพิ่มเติมหลังการเข้าร่วมการส่งคืน applorstatustoken ใหม่ (SecurityContextholder.getContext () SecurityConTexTholder.getContext ();ดังที่เห็นได้จากด้านบนเพื่อให้ได้การรับรองความถูกต้องแบบไดนามิกเราสามารถเริ่มต้นจากสองด้าน:
มาดูวิธีการใช้งานแยกกัน
Custom AccessDecisionManager
AccessDecisionManagers อย่างเป็นทางการทั้งสามนั้นขึ้นอยู่กับ AccessDecisionVoter เพื่อใช้การรับรองความถูกต้องของการอนุญาตดังนั้นเราจึงต้องปรับแต่ง AccessDecisionVoter เท่านั้น
การปรับแต่งส่วนใหญ่ใช้อินเตอร์เฟส AccessDecisionVoter เราสามารถใช้งาน Rolevoter อย่างเป็นทางการต่อไปนี้:
Public Class RoleBasedVoter ใช้ AccessDecisionVoter <Object> {@Override Public Boolean รองรับ (แอตทริบิวต์ configattribute) {return true; } @Override การโหวต INT สาธารณะ (การรับรองความถูกต้องการรับรองความถูกต้องวัตถุวัตถุคอลเลกชัน <COFINTTRIBUTE> แอตทริบิวต์) {ถ้า (การรับรองความถูกต้อง == null) {return access_denied; } int result = access_abstain; คอลเลกชัน <? ขยาย Grantedauthority> เจ้าหน้าที่ = Extractauthorities (การตรวจสอบ); สำหรับ (configattribute attribute: attributes) {if (attribute.getAttribute () == null) {ดำเนินการต่อ; } if (this.supports (แอตทริบิวต์)) {result = access_denied; // พยายามค้นหาอำนาจที่ได้รับการจับคู่สำหรับ (Grantedauthority Authority: เจ้าหน้าที่) {ถ้า (attribute.getAttribute (). Equals (Authority.getauthority ())) {return access_granted; }}}} ผลการส่งคืน; } คอลเลกชัน <? ขยาย GrantedAuthority> Extractauthorities (การรับรองความถูกต้องของการรับรองความถูกต้อง) {return Authentication.getAuthorities (); } @Override บูลีนสาธารณะรองรับ (คลาส Clazz) {return true; -จะเพิ่มสิทธิ์แบบไดนามิกได้อย่างไร?
ประเภทของวัตถุวัตถุใน vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) คือ FilterInVocation และคุณสามารถรับ URL ของคำขอปัจจุบันผ่าน GetRequesturl:
วัตถุ FilterInVocation FI = (FilterInVocation); String url = fi.getRequesturl ();
ดังนั้นจึงมีพื้นที่สำหรับการขยายตัวมากมายที่นี่ คุณสามารถโหลดแบบไดนามิกจากฐานข้อมูลจากนั้นตัดสินการกำหนดค่าของ URL
จะใช้ RoleBasedVoter นี้ได้อย่างไร? ใช้วิธี AccessDecisionManager เพื่อปรับแต่งในการกำหนดค่า เราควรใช้เป็นเอกฉันท์จากนั้นเพิ่ม RoleBasedVoter ที่กำหนดเอง
@enableWebsecurity @enableGlobalMethodSecurity (prepOstenabled = true, securedenabled = true) ระดับความปลอดภัยระดับสาธารณะขยายการขยาย WebSecurityConfigurerAdapter {@Override Void Proftected (httpsecurity http) .ExceptionHandling () .AuthenticationEntryPoint (ปัญหาสำคัญ) .AccessDeniedHandler (ปัญหาสนับสนุน). และ () .csrf (). disable () .headers () .frameoptions (). และ (). Custom AccessDecisionManager .AccessDecisionManager (AccessDecisionManager ()). และ () .Apply (SecurityConfigurerAdapter ()); } @Bean Public AccessDecisionAger AccessDecisionManager () {รายการ <AccessDecisionVoter <? ขยาย Object >> DecisionVoters = array.aslist (ใหม่ WebExpressionVoter (), // ใหม่ Rolevoter (), RoleBasedVoter ใหม่ (), AuthenticativeVoter ใหม่ ()); กลับมาเป็นเอกฉันท์ใหม่ (DecisionVoters); -ปรับแต่ง SecurityMetAdatasource
Custom FilterInvocationsecurityMetAdataSource จำเป็นต้องใช้อินเตอร์เฟสเท่านั้นและการโหลดกฎแบบไดนามิกจาก DB ในอินเทอร์เฟซ
เพื่อนำคำจำกัดความกลับมาใช้ใหม่ในรหัสเราสามารถใช้ SecurityMetAdataSource ที่สร้างขึ้นในรหัสและส่งผ่านใน FilterInVocationSecurityMetAdataSource เริ่มต้นในตัวสร้าง
คลาสสาธารณะ AppFilterInvocationsecurityMetAdataSource ดำเนินการ org.springframework.security.web.access.intercept.filterinvocationsecuritymetadatasource {private filterinvocationsecuritymetadatasource supermetadatasource; @Override Public Collection <Configattribute> GetAllConfigattributes () {return null; } Public AppFilterInvocationsEcurityMetAdataSource (FilterInVocationSecurityMetAdataSource ExpressionBasedFilterInVocationSecurityMetAdataSource) {this.SuperMetAdataSource = ExpressionBasedFilterInvocationsecurityMetAdataTaTaTaTaTaTaTaTaTaTaTaTaTaTaTaTaTaTaTaDataTaTa // TODO การกำหนดค่าการอนุญาตโหลดจากฐานข้อมูล} ส่วนตัว antpathmatcher ANTPathmatcher = ใหม่ antaphatmatcher (); // ที่นี่คุณต้องโหลดแผนที่สุดท้ายส่วนตัว <สตริงสตริง> urlrolemap = ใหม่ hashmap <string, string> () {{put ("/open/**", "role_anonymous"); ใส่ ("/สุขภาพ", "role_anonymous"); ใส่ ("/รีสตาร์ท", "role_admin"); ใส่ ("/สาธิต", "role_user"); - @Override Public Collection <ConfigAttribute> getAttributes (วัตถุวัตถุ) พ่น unledalArgumentException {filterInvocation fi = (filterInvocation) วัตถุ; String url = fi.getRequesturl (); สำหรับ (map.entry <string, string> รายการ: urlrolemap.entryset ()) {ถ้า (antaphmatcher.match (entry.getKey (), url)) {return securityConfig.createlist (entry.getValue ()); }} // ส่งคืนการกำหนดค่าเริ่มต้นที่กำหนดโดยรหัสส่งคืน supermetadatasource.getattributes (วัตถุ); } @Override บูลีนสาธารณะรองรับ (คลาส <?> clazz) {return filterinvocation.class.isassignablefrom (clazz); -ใช้อย่างไร? ซึ่งแตกต่างจาก AccessDecisionManager, ExpressionUrlauthorizationConfigurer ไม่ได้จัดเตรียมวิธีการที่กำหนดไว้เพื่อตั้งค่า FilterInVocationSecurityMetAdataSource ของ FiltersecurityInterceptor วิธีการทำอย่างไร?
ค้นพบวิธีการขยายด้วย ObjectPostProcessor ซึ่งปรับแต่ง ObjectPostProcessor ที่จัดการประเภท FiltersecurityInterceptor คุณสามารถแก้ไข FiltersecurityInterceptor ได้
@enableWebsecurity @enableGlobalMethodSecurity (prepOstenabled = true, securedenabled = true) ระดับความปลอดภัยระดับสาธารณะขยายการขยาย WebSecurityConfigurerAdapter {@Override Void Proftected (httpsecurity http) .ExceptionHandling () .AuthenticationEntryPoint (ปัญหาสำคัญ) .AccessDeniedHandler (ปัญหาสนับสนุน). และ () .csrf (). disable () .headers () .frameoptions (). และ (). FilterInVocationSecurityMetAdAtAsource .WithOwjectPostProcessor (ObjectPostProcessor <FiltersecurityInterceptor> () {@Override สาธารณะ <o ขยาย FiltersecurityInterceptor> o postprocess (o fsi) { fsi.setsecuritymetadatasource (mysecuritymetadatasource (fsi.getsecuritymetadatasource ()); } @Bean Public AppFilterInvocationsEcurityMetAdataSource MySecurityMetAdataSource (FilterInVocationSecurityMetAdataSource FilterInvocationsecurityMetAdataSource) AppFilterInvocationsecurityMetAdatasource (FilterInVocationSecurityMetAdatasource); ส่งคืนความปลอดภัย metadatasource;}สรุป
บทความนี้แนะนำสองวิธีในการใช้การอนุญาตแบบไดนามิกตามความปลอดภัยของฤดูใบไม้ผลิ หนึ่งคือการปรับแต่ง AccessDecisionManager และอื่น ๆ คือการปรับแต่ง FilterInVocationSecurityMetAdataSource คุณสามารถเลือกได้อย่างยืดหยุ่นตามความต้องการของคุณในโครงการจริง
การอ่านเพิ่มเติม:
สถาปัตยกรรมความปลอดภัยในฤดูใบไม้ผลิและการวิเคราะห์รหัสที่มา
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com