Spring Security Filter Chain ทำงานอย่างไร


136

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

ตัวกรองหลักในห่วงโซ่คือ (ตามลำดับ)

  • SecurityContextPersistenceFilter (กู้คืนการพิสูจน์ตัวตนจาก JSESSIONID)
  • UsernamePasswordAuthenticationFilter (ดำเนินการตรวจสอบสิทธิ์)
  • ExceptionTranslationFilter (จับข้อยกเว้นด้านความปลอดภัยจาก FilterSecurityInterceptor)
  • FilterSecurityInterceptor (อาจมีข้อยกเว้นในการพิสูจน์ตัวตนและการอนุญาต)

ฉันสับสนว่าตัวกรองเหล่านี้ใช้อย่างไร สำหรับการเข้าสู่ระบบแบบฟอร์มที่มีให้ในฤดูใบไม้ผลิUsernamePasswordAuthenticationFilterจะใช้สำหรับ/ loginเท่านั้นและตัวกรองหลังไม่ได้ใช่หรือไม่? ที่ไม่ใช้แบบฟอร์มการเข้าสู่ระบบองค์ประกอบ namespace อัตโนมัติกำหนดค่าตัวกรองเหล่านี้หรือไม่ ทุกคำขอ (รับรองความถูกต้องหรือไม่) เข้าถึงFilterSecurityInterceptorสำหรับ URL ที่ไม่เข้าสู่ระบบหรือไม่

จะเกิดอะไรขึ้นถ้าฉันต้องการรักษาความปลอดภัย REST API ด้วยJWT-tokenซึ่งดึงมาจากการเข้าสู่ระบบ? ฉันต้องกำหนดค่าhttpแท็กคอนฟิกูเรชันเนมสเปซสองแท็กสิทธิ์? หนึ่งสำหรับการเข้าสู่ระบบ /ด้วยUsernamePasswordAuthenticationFilterและอีกคนหนึ่งสำหรับส่วนที่เหลือของ URL JwtAuthenticationFilterกับที่กำหนดเอง

การกำหนดค่าสองhttpองค์ประกอบสร้างสองspringSecurityFitlerChainsหรือไม่ ถูกUsernamePasswordAuthenticationFilterปิดโดยปริยายจนผมประกาศform-login? ฉันจะแทนที่SecurityContextPersistenceFilterด้วยตัวกรองซึ่งจะได้รับAuthenticationจากที่มีอยู่JWT-tokenแทนที่จะเป็นJSESSIONIDอย่างไร


ลำดับเริ่มต้นของตัวกรองถูกกำหนดไว้ใน
org.springframework.security.config.annotation.web.builders.FilterComparator

คำตอบ:


211

ห่วงโซ่ตัวกรองความปลอดภัยของสปริงเป็นเครื่องยนต์ที่ซับซ้อนและยืดหยุ่นมาก

ตัวกรองหลักในห่วงโซ่คือ (ตามลำดับ)

  • SecurityContextPersistenceFilter (กู้คืนการพิสูจน์ตัวตนจาก JSESSIONID)
  • UsernamePasswordAuthenticationFilter (ดำเนินการตรวจสอบสิทธิ์)
  • ExceptionTranslationFilter (จับข้อยกเว้นด้านความปลอดภัยจาก FilterSecurityInterceptor)
  • FilterSecurityInterceptor (อาจมีข้อยกเว้นในการพิสูจน์ตัวตนและการอนุญาต)

เมื่อดูเอกสารรุ่นที่เสถียร 4.2.1 ในปัจจุบันส่วนที่13.3 การสั่งกรองคุณจะเห็นองค์กรตัวกรองทั้งหมดของห่วงโซ่ตัวกรอง:

13.3 ลำดับตัวกรอง

ลำดับที่ตัวกรองกำหนดไว้ในห่วงโซ่มีความสำคัญมาก ไม่ว่าคุณจะใช้ตัวกรองใดจริงลำดับควรเป็นดังนี้:

  1. ChannelProcessingFilterเนื่องจากอาจต้องเปลี่ยนเส้นทางไปยังโปรโตคอลอื่น

  2. SecurityContextPersistenceFilterดังนั้นจึงสามารถตั้งค่า SecurityContext ใน SecurityContextHolder ที่จุดเริ่มต้นของคำขอเว็บและการเปลี่ยนแปลงใด ๆ ใน SecurityContext สามารถคัดลอกไปยัง HttpSession เมื่อคำขอเว็บสิ้นสุดลง (พร้อมสำหรับการใช้งานกับคำขอเว็บถัดไป)

  3. ConcurrentSessionFilterเนื่องจากใช้ฟังก์ชัน SecurityContextHolder และจำเป็นต้องอัปเดต SessionRegistry เพื่อสะท้อนการร้องขอต่อเนื่องจากหลัก

  4. กลไกการประมวลผลการพิสูจน์ตัวตน - UsernamePasswordAuthenticationFilter , CasAuthenticationFilter , BasicAuthenticationFilterฯลฯ - เพื่อให้ SecurityContextHolder สามารถแก้ไขเพื่อให้มีโทเค็นการร้องขอการพิสูจน์ตัวตนที่ถูกต้อง

  5. SecurityContextHolderAwareRequestFilterถ้าคุณจะใช้มันในการติดตั้งระบบรักษาความปลอดภัยในฤดูใบไม้ผลิตระหนัก HttpServletRequestWrapper ลงในภาชนะ servlet ของคุณ

  6. JaasApiIntegrationFilterถ้าJaasAuthenticationTokenอยู่ใน SecurityContextHolder นี้จะดำเนินการ FilterChain เป็นเรื่องใน JaasAuthenticationToken

  7. RememberMeAuthenticationFilterดังนั้นหากไม่มีกลไกการประมวลผลการพิสูจน์ตัวตนก่อนหน้านี้ได้อัปเดต SecurityContextHolder และคำขอแสดงคุกกี้ที่ช่วยให้สามารถใช้บริการ remember-me ได้จะมีการใส่อ็อบเจ็กต์ Authentication ที่จำได้อย่างเหมาะสมไว้ที่นั่น

  8. AnonymousAuthenticationFilterดังนั้นหากไม่มีกลไกการประมวลผลการพิสูจน์ตัวตนก่อนหน้านี้อัพเดต SecurityContextHolder อ็อบเจ็กต์การพิสูจน์ตัวตนแบบไม่ระบุชื่อจะถูกวางไว้ที่นั่น

  9. ExceptionTranslationFilterเพื่อตรวจจับข้อยกเว้น Spring Security เพื่อให้สามารถส่งคืนการตอบสนองข้อผิดพลาด HTTP หรือสามารถเรียกใช้ AuthenticationEntryPoint ที่เหมาะสมได้

  10. FilterSecurityInterceptorเพื่อป้องกัน URI ของเว็บและเพิ่มข้อยกเว้นเมื่อการเข้าถึงถูกปฏิเสธ

ตอนนี้ฉันจะพยายามตอบคำถามของคุณทีละคำถาม:

ฉันสับสนว่าตัวกรองเหล่านี้ใช้อย่างไร สำหรับการเข้าสู่ระบบแบบฟอร์มที่มีให้ในฤดูใบไม้ผลิ UsernamePasswordAuthenticationFilter จะใช้สำหรับ / login เท่านั้นและตัวกรองหลังไม่ได้ใช่หรือไม่? องค์ประกอบเนมสเปซแบบฟอร์มล็อกอินกำหนดค่าตัวกรองเหล่านี้โดยอัตโนมัติหรือไม่ ทุกคำขอ (รับรองความถูกต้องหรือไม่) เข้าถึง FilterSecurityInterceptor สำหรับ URL ที่ไม่เข้าสู่ระบบหรือไม่

เมื่อคุณกำหนดค่า<security-http>ส่วนสำหรับแต่ละส่วนคุณต้องระบุกลไกการพิสูจน์ตัวตนอย่างน้อยหนึ่งรายการ ต้องเป็นหนึ่งในตัวกรองที่ตรงกับกลุ่ม 4 ในส่วน 13.3 Filter Ordering จากเอกสาร Spring Security ที่ฉันเพิ่งอ้างถึง

นี่คือองค์ประกอบความปลอดภัยขั้นต่ำที่ถูกต้อง: http ซึ่งสามารถกำหนดค่าได้:

<security:http authentication-manager-ref="mainAuthenticationManager" 
               entry-point-ref="serviceAccessDeniedHandler">
    <security:intercept-url pattern="/sectest/zone1/**" access="hasRole('ROLE_ADMIN')"/>
</security:http>

เพียงแค่ทำมันตัวกรองเหล่านี้ได้รับการกำหนดค่าในพร็อกซีตัวกรอง:

{
        "1": "org.springframework.security.web.context.SecurityContextPersistenceFilter",
        "2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter",
        "3": "org.springframework.security.web.header.HeaderWriterFilter",
        "4": "org.springframework.security.web.csrf.CsrfFilter",
        "5": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter",
        "6": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter",
        "7": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter",
        "8": "org.springframework.security.web.session.SessionManagementFilter",
        "9": "org.springframework.security.web.access.ExceptionTranslationFilter",
        "10": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor"
    }

หมายเหตุ: ฉันได้รับพวกเขาโดยการสร้าง RestController แบบง่ายซึ่ง @Autowires FilterChainProxy และส่งคืนเนื้อหา:

    @Autowired
    private FilterChainProxy filterChainProxy;

    @Override
    @RequestMapping("/filterChain")
    public @ResponseBody Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){
        return this.getSecurityFilterChainProxy();
    }

    public Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){
        Map<Integer, Map<Integer, String>> filterChains= new HashMap<Integer, Map<Integer, String>>();
        int i = 1;
        for(SecurityFilterChain secfc :  this.filterChainProxy.getFilterChains()){
            //filters.put(i++, secfc.getClass().getName());
            Map<Integer, String> filters = new HashMap<Integer, String>();
            int j = 1;
            for(Filter filter : secfc.getFilters()){
                filters.put(j++, filter.getClass().getName());
            }
            filterChains.put(i++, filters);
        }
        return filterChains;
    }

ที่นี่เราจะเห็นว่าเพียงแค่ประกาศ<security:http>องค์ประกอบด้วยการกำหนดค่าขั้นต่ำเพียงรายการเดียวตัวกรองเริ่มต้นทั้งหมดจะรวมอยู่ด้วย แต่ไม่มีตัวกรองใดที่เป็นประเภทการตรวจสอบความถูกต้อง (กลุ่มที่ 4 ในส่วนลำดับตัวกรอง 13.3) ดังนั้นจึงหมายความว่าเพียงแค่ประกาศsecurity:httpองค์ประกอบเท่านั้น SecurityContextPersistenceFilter, ExceptionTranslationFilter และ FilterSecurityInterceptor จะได้รับการกำหนดค่าโดยอัตโนมัติ

ในความเป็นจริงควรกำหนดค่ากลไกการประมวลผลการพิสูจน์ตัวตนอย่างใดอย่างหนึ่งและแม้แต่การประมวลผลเนมสเปซการรักษาความปลอดภัยก็อ้างว่าเกิดข้อผิดพลาดระหว่างการเริ่มต้น แต่สามารถข้ามการเพิ่มแอตทริบิวต์จุดเริ่มต้น - จุดอ้างอิงใน <http:security>

หากฉันเพิ่มพื้นฐาน<form-login>ในการกำหนดค่าด้วยวิธีนี้:

<security:http authentication-manager-ref="mainAuthenticationManager">
    <security:intercept-url pattern="/sectest/zone1/**" access="hasRole('ROLE_ADMIN')"/>
    <security:form-login />
</security:http>

ตอนนี้ filterChain จะเป็นดังนี้:

{
        "1": "org.springframework.security.web.context.SecurityContextPersistenceFilter",
        "2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter",
        "3": "org.springframework.security.web.header.HeaderWriterFilter",
        "4": "org.springframework.security.web.csrf.CsrfFilter",
        "5": "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter",
        "6": "org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter",
        "7": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter",
        "8": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter",
        "9": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter",
        "10": "org.springframework.security.web.session.SessionManagementFilter",
        "11": "org.springframework.security.web.access.ExceptionTranslationFilter",
        "12": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor"
    }

ตอนนี้สองตัวกรองorg.springframework.security.web.authentication.UsernamePasswordAuthenticationFilterและ org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter ถูกสร้างและกำหนดค่าใน FilterChainProxy

ตอนนี้คำถาม:

สำหรับการเข้าสู่ระบบแบบฟอร์มที่มีให้ในฤดูใบไม้ผลิ UsernamePasswordAuthenticationFilter จะใช้สำหรับ / login เท่านั้นและตัวกรองหลังไม่ได้ใช่หรือไม่?

ใช่มันถูกใช้เพื่อพยายามดำเนินการตามกลไกการประมวลผลการเข้าสู่ระบบในกรณีที่คำขอตรงกับ URL ของ UsernamePasswordAuthenticationFilter URL นี้สามารถกำหนดค่าหรือปรับเปลี่ยนพฤติกรรมให้ตรงกับทุกคำขอ

คุณอาจมีกลไกการประมวลผลการพิสูจน์ตัวตนมากกว่าหนึ่งตัวที่กำหนดค่าไว้ใน FilterchainProxy เดียวกัน (เช่น HttpBasic, CAS ฯลฯ )

องค์ประกอบเนมสเปซแบบฟอร์มล็อกอินกำหนดค่าตัวกรองเหล่านี้โดยอัตโนมัติหรือไม่

ไม่องค์ประกอบการเข้าสู่ระบบแบบฟอร์มจะกำหนดค่า UsernamePasswordAUthenticationFilter และในกรณีที่คุณไม่ได้ระบุ url หน้าการเข้าสู่ระบบมันยังกำหนดค่า org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter ซึ่งจะสิ้นสุดในการเข้าสู่ระบบที่สร้างขึ้นโดยอัตโนมัติ หน้า.

ตัวกรองอื่น ๆ ได้รับการกำหนดค่าโดยอัตโนมัติตามค่าเริ่มต้นเพียงแค่สร้าง<security:http>องค์ประกอบที่ไม่มีsecurity:"none"แอตทริบิวต์

ทุกคำขอ (รับรองความถูกต้องหรือไม่) เข้าถึง FilterSecurityInterceptor สำหรับ URL ที่ไม่เข้าสู่ระบบหรือไม่

ทุกคำขอควรไปถึงเนื่องจากเป็นองค์ประกอบที่ดูแลว่าคำขอมีสิทธิ์เข้าถึง URL ที่ร้องขอหรือไม่ FilterChain.doFilter(request, response);แต่บางส่วนของฟิลเตอร์ประมวลผลก่อนอาจหยุดการประมวลผลห่วงโซ่ตัวกรองก็ไม่เรียก ตัวอย่างเช่นตัวกรอง CSRF อาจหยุดการประมวลผลโซ่ตัวกรองหากคำขอไม่มีพารามิเตอร์ csrf

จะเกิดอะไรขึ้นถ้าฉันต้องการรักษาความปลอดภัย REST API ด้วย JWT-token ซึ่งดึงมาจากการเข้าสู่ระบบ? ฉันต้องกำหนดค่าแท็ก http การกำหนดค่าเนมสเปซสองรายการสิทธิ์? อีกคนหนึ่งสำหรับ / เข้าสู่ระบบด้วยUsernamePasswordAuthenticationFilterและอีกคนหนึ่งสำหรับส่วนที่เหลือของ URL JwtAuthenticationFilterกับที่กำหนดเอง

ไม่คุณไม่ได้บังคับให้ทำแบบนี้ คุณสามารถประกาศทั้งสองUsernamePasswordAuthenticationFilterและJwtAuthenticationFilterในองค์ประกอบ http เดียวกันได้ แต่ขึ้นอยู่กับลักษณะการทำงานที่เป็นรูปธรรมของแต่ละตัวกรองนี้ ทั้งสองแนวทางเป็นไปได้และวิธีใดที่จะเลือกได้ในที่สุดก็ขึ้นอยู่กับความชอบของตัวเอง

การกำหนดค่าองค์ประกอบ http สองรายการจะสร้าง springSecurityFitlerChains สองรายการหรือไม่

ใช่นั่นเป็นความจริง

UsernamePasswordAuthenticationFilter ถูกปิดโดยค่าเริ่มต้นหรือไม่จนกว่าฉันจะประกาศเข้าสู่ระบบแบบฟอร์ม?

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

ฉันจะแทนที่ SecurityContextPersistenceFilter ได้อย่างไรซึ่งจะได้รับการรับรองความถูกต้องจากโทเค็น JWT ที่มีอยู่แทนที่จะเป็น JSESSIONID

คุณสามารถหลีกเลี่ยง SecurityContextPersistenceFilter ได้เพียงกำหนดค่ากลยุทธ์เซสชันใน<http:element>. เพียงกำหนดค่าดังนี้:

<security:http create-session="stateless" >

หรือในกรณีนี้คุณสามารถเขียนทับด้วยตัวกรองอื่นด้วยวิธีนี้ภายใน<security:http>องค์ประกอบ:

<security:http ...>  
   <security:custom-filter ref="myCustomFilter" position="SECURITY_CONTEXT_FILTER"/>    
</security:http>
<beans:bean id="myCustomFilter" class="com.xyz.myFilter" />

แก้ไข:

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

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

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

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

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

ดังนั้นฉันคิดว่าเป็นที่ชัดเจนว่าทั้งจำนวนตัวกรองการตรวจสอบสิทธิ์จะไม่กำหนดจำนวนผู้ให้บริการการตรวจสอบสิทธิ์หรือจำนวนผู้ให้บริการเป็นตัวกำหนดจำนวนตัวกรอง

นอกจากนี้เอกสารประกอบยังระบุว่า SecurityContextPersistenceFilter มีหน้าที่ทำความสะอาด SecurityContext ซึ่งมีความสำคัญเนื่องจากการรวมเธรด หากฉันละเว้นหรือให้การใช้งานแบบกำหนดเองฉันต้องดำเนินการทำความสะอาดด้วยตนเองใช่ไหม มี gotcha ที่คล้ายกันมากขึ้นเมื่อปรับแต่งโซ่หรือไม่?

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

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


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

นอกจากนี้เอกสารประกอบยังระบุว่า SecurityContextPersistenceFilter มีหน้าที่ทำความสะอาด SecurityContext ซึ่งมีความสำคัญเนื่องจากการรวมเธรด หากฉันละเว้นหรือให้การใช้งานแบบกำหนดเองฉันต้องดำเนินการทำความสะอาดด้วยตนเองใช่ไหม มี gotcha ที่คล้ายกันมากขึ้นเมื่อปรับแต่งโซ่หรือไม่?
Tuomas Toivonen

1
@TuomasToivonen ฉันแก้ไขคำตอบของฉันหลังจากคำถามในความคิดเห็นล่าสุดของคุณ
jlumietu

1
@jlumietu มีคำพูดที่ขาดหายไปในคำอธิบายประกอบ java ถัดจาก("/ filterChain)คุณวางวิธีนี้ไว้ที่ไหนฉันได้ลองเพิ่มลงในคอนโทรลเลอร์แล้วและฉันมี:No qualifying bean of type 'org.springframework.security.web.FilterChainProxy' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Dimitri Kopriwa

@BigDong ตรวจสอบให้แน่ใจว่าคุณได้ประกาศ SpringSecurityFilterChain ทั้งใน web.xml หรือ java webapp config และในการกำหนดค่าสปริงของคุณ ข้อมูลโค้ดนี้จะต้องรวมอยู่ในคอนโทรลเลอร์เช่นเดียวกับที่คุณทำ และใช่คุณกำลังเขียนเกี่ยวกับคำพูดที่หายไป
jlumietu

4

UsernamePasswordAuthenticationFilterใช้สำหรับ/loginเท่านั้นและตัวกรองหลังไม่ใช่?

ไม่UsernamePasswordAuthenticationFilterขยายAbstractAuthenticationProcessingFilterและนี่มีRequestMatcherนั่นหมายความว่าคุณสามารถกำหนด URL ประมวลผลของคุณเองกรองนี้เท่านั้นจัดการRequestMatcherกับ URL คำขอ URL /loginที่เริ่มต้นคือการประมวลผล

ฟิลเตอร์หลังจากนั้นยังคงสามารถจัดการการร้องขอถ้ารันUsernamePasswordAuthenticationFilterchain.doFilter(request, response);

รายละเอียดเพิ่มเติมเกี่ยวกับอุปกรณ์ประกอบหลัก

องค์ประกอบเนมสเปซแบบฟอร์มล็อกอินกำหนดค่าตัวกรองเหล่านี้โดยอัตโนมัติหรือไม่

UsernamePasswordAuthenticationFilterถูกสร้างขึ้นโดย<form-login>สิ่งเหล่านี้คือนามแฝงตัวกรองมาตรฐานและการสั่งซื้อ

ทุกคำขอ (รับรองความถูกต้องหรือไม่) เข้าถึง FilterSecurityInterceptor สำหรับ URL ที่ไม่เข้าสู่ระบบหรือไม่

ขึ้นอยู่กับว่าก่อนฟิตเลอร์จะประสบความสำเร็จหรือไม่ แต่ฟิตเลอร์FilterSecurityInterceptorคนสุดท้ายตามปกติ

การกำหนดค่าองค์ประกอบ http สองรายการจะสร้าง springSecurityFitlerChains สองรายการหรือไม่

ใช่ FitlerChain ทุกตัวมี a RequestMatcherหากRequestMatcherตรงกับคำขอผู้สวมใส่ในห่วงโซ่ของ Fitler จะจัดการคำขอ

ค่าเริ่มต้นจะRequestMatcherตรงกับคำขอทั้งหมดหากคุณไม่ได้กำหนดค่ารูปแบบหรือคุณสามารถกำหนดค่า url เฉพาะ ( <http pattern="/rest/**") ได้

หากคุณต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับ Fitlers ฉันคิดว่าคุณสามารถตรวจสอบซอร์สโค้ดได้ในการรักษาความปลอดภัยในฤดูใบไม้ผลิ doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)


4

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

ลำดับการดำเนินการใน Spring Security

  1. WebAsyncManagerIntegrationFilter จัดเตรียมการรวมระหว่าง SecurityContext และ WebAsyncManager ของ Spring Web

  2. SecurityContextPersistenceFilterตัวกรองนี้จะดำเนินการเพียงครั้งเดียวต่อคำขอเติมข้อมูล SecurityContextHolder ด้วยข้อมูลที่ได้รับจาก SecurityContextRepository ที่กำหนดค่าไว้ก่อนหน้าคำขอและจัดเก็บกลับในที่เก็บเมื่อคำขอเสร็จสิ้นและล้างตัวยึดบริบท
    มีการตรวจสอบคำขอสำหรับเซสชันที่มีอยู่ หากคำขอใหม่ SecurityContext จะถูกสร้างขึ้นอย่างอื่นถ้าขอได้แล้วเซสชั่นการรักษาความปลอดภัยบริบทที่มีอยู่จะได้รับจาก respository

  3. HeaderWriterFilter กรองการนำไปใช้เพื่อเพิ่มส่วนหัวในการตอบกลับปัจจุบัน

  4. LogoutFilterหาก url คำขอเป็น/logout(สำหรับการกำหนดค่าเริ่มต้น) หรือหากRequestMatcherกำหนดURL ตามคำขอที่กำหนดค่าไว้LogoutConfigurerแล้ว

    • ล้างบริบทความปลอดภัย
    • ทำให้เซสชันไม่ถูกต้อง
    • ลบคุกกี้ทั้งหมดที่มีชื่อคุกกี้ที่กำหนดค่าไว้ LogoutConfigurer
    • เปลี่ยนเส้นทางไปยัง URL ความสำเร็จในการออกจากระบบเริ่มต้น /หรือ URL ความสำเร็จในการออกจากระบบที่กำหนดค่าหรือเรียกใช้การกำหนดค่า logoutSuccessHandler
  5. UsernamePasswordAuthenticationFilter

    • สำหรับ url คำขอใด ๆ นอกเหนือจาก loginProcessingUrl ตัวกรองนี้จะไม่ประมวลผลเพิ่มเติม แต่เชนตัวกรองจะดำเนินต่อไป
    • หาก URL ที่ร้องขอตรงกับ (ต้องเป็นHTTP POST) ค่าเริ่มต้น/loginหรือ.loginProcessingUrl()กำหนดค่าการจับคู่FormLoginConfigurerแล้วUsernamePasswordAuthenticationFilterพยายามตรวจสอบสิทธิ์
    • พารามิเตอร์แบบฟอร์มการเข้าสู่ระบบเริ่มต้นมีชื่อผู้ใช้และรหัสผ่านที่สามารถแทนที่โดย,usernameParameter(String)passwordParameter(String)
    • การตั้งค่า.loginPage() ลบล้างค่าเริ่มต้น
    • ขณะพยายามตรวจสอบสิทธิ์
      • มีการสร้างAuthenticationออบเจ็กต์ ( UsernamePasswordAuthenticationTokenหรือการนำไปใช้Authenticationในกรณีของตัวกรองการตรวจสอบสิทธิ์ที่กำหนดเองของคุณ)
      • และauthenticationManager.authenticate(authToken)จะถูกเรียก
      • โปรดทราบว่าเราสามารถกำหนดค่าAuthenticationProviderวิธีการรับรองความถูกต้องจำนวนเท่าใดก็ได้โดยพยายามให้ผู้ให้บริการรับรองความถูกต้องทั้งหมดและตรวจสอบsupportsวัตถุ authToken / authentication ของผู้ให้บริการ auth ใด ๆ โดยจะใช้ผู้ให้บริการ auth ที่สนับสนุนสำหรับการตรวจสอบสิทธิ์ AuthenticationExceptionและส่งกลับวัตถุรับรองความถูกต้องในกรณีที่ประสบความสำเร็จของการตรวจสอบอื่นพ่น
    • หากเซสชันความสำเร็จในการพิสูจน์ตัวตนจะถูกสร้างขึ้นและauthenticationSuccessHandlerจะถูกเรียกซึ่งเปลี่ยนเส้นทางไปยัง URL เป้าหมายที่กำหนดค่าไว้ (ค่าเริ่มต้นคือ/)
    • หากการพิสูจน์ตัวตนล้มเหลวผู้ใช้จะกลายเป็นผู้ใช้ที่ไม่ได้รับการพิสูจน์ตัวตนและโซ่จะดำเนินต่อไป
  6. SecurityContextHolderAwareRequestFilterหากคุณกำลังใช้เพื่อติดตั้ง Spring Security ทราบ HttpServletRequestWrapper ลงในคอนเทนเนอร์ servlet ของคุณ

  7. AnonymousAuthenticationFilterตรวจพบว่าไม่มีวัตถุรับรองความถูกต้องใน SecurityContextHolder หากไม่มีการตรวจสอบวัตถุที่พบสร้างAuthenticationวัตถุ ( AnonymousAuthenticationToken) ROLE_ANONYMOUSมีอำนาจที่ได้รับ ที่นี่AnonymousAuthenticationTokenช่วยอำนวยความสะดวกในการระบุคำขอที่ตามมาของผู้ใช้ที่ไม่ได้รับการพิสูจน์ตัวตน

บันทึกการแก้ไขข้อบกพร่อง
DEBUG - /app/admin/app-config at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@aeef7b36: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS' 
  1. ExceptionTranslationFilterเพื่อตรวจจับข้อยกเว้น Spring Security เพื่อให้สามารถส่งคืนการตอบสนองข้อผิดพลาด HTTP หรือสามารถเรียกใช้ AuthenticationEntryPoint ที่เหมาะสม

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

พิจารณาข้อยกเว้น 401-UnAuthorized และ 403-Forbidden การตัดสินใจเหล่านี้จะทำในลำดับสุดท้ายในห่วงโซ่ตัวกรอง

  • ผู้ใช้ที่ไม่ได้รับรองความถูกต้องพยายามเข้าถึงทรัพยากรสาธารณะ - อนุญาต
  • ผู้ใช้ที่ไม่ได้รับรองความถูกต้องพยายามเข้าถึงทรัพยากรที่ปลอดภัย - 401-UnAuthorized
  • ผู้ใช้ที่พิสูจน์ตัวตนพยายามเข้าถึงทรัพยากรที่ จำกัด (ถูก จำกัด สำหรับบทบาทของเขา) - 403-Forbidden

หมายเหตุ: คำขอของผู้ใช้กระแสไม่เพียง แต่ในข้างต้นฟิลเตอร์กล่าวถึง แต่มีคนอื่น ๆ ฟิลเตอร์เกินไปไม่ได้แสดงที่นี่ (. ConcurrentSessionFilter, RequestCacheAwareFilter, SessionManagementFilter... ) มันจะแตกต่างกันเมื่อคุณใช้ตัวกรองการตรวจสอบสิทธิ์ของคุณเองแทน
จะแตกต่างกันไปหากคุณกำหนดค่าตัวกรองการตรวจสอบสิทธิ์ JWT และละเว้นจะกลายเป็นกรณีที่แตกต่างกันอย่างสิ้นเชิง UsernamePasswordAuthenticationFilter
.formLogin() i.e, UsernamePasswordAuthenticationFilter


เพียงเพื่อการอ้างอิง ตัวกรองใน spring-web และ spring-security
หมายเหตุ: อ้างอิงชื่อแพ็คเกจในรูปเนื่องจากมีตัวกรองอื่น ๆ จาก orm และตัวกรองที่ใช้งานแบบกำหนดเองของฉัน

ป้อนคำอธิบายภาพที่นี่

จากการจัดลำดับเอกสารของตัวกรองจะได้รับเป็น

  • ChannelProcessingFilter
  • ConcurrentSessionFilter
  • SecurityContextPersistenceFilter
  • LogoutFilter
  • X509AuthenticationFilter
  • AbstractPreAuthenticatedProcessingFilter
  • CasAuthenticationFilter
  • UsernamePasswordAuthenticationFilter
  • ConcurrentSessionFilter
  • OpenIDAuthenticationFilter
  • DefaultLoginPageGeneratingFilter
  • DefaultLogoutPageGeneratingFilter
  • ConcurrentSessionFilter
  • DigestAuthenticationFilter
  • BearerTokenAuthenticationFilter
  • BasicAuthenticationFilter
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • JaasApiIntegrationFilter
  • RememberMeAuthenticationFilter
  • AnonymousAuthenticationFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • SwitchUserFilter

คุณยังสามารถอ้างอิง
วิธีที่ใช้บ่อยที่สุดในการตรวจสอบเว็บแอปที่ทันสมัย?
ความแตกต่างระหว่างการพิสูจน์ตัวตนและการอนุญาตในบริบทของ Spring Security?

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