มีการเปลี่ยนแปลงมากมายในโลกฤดูใบไม้ผลิตั้งแต่ตอบคำถามนี้ Spring ทำให้ผู้ใช้ปัจจุบันอยู่ในคอนโทรลเลอร์ได้ง่ายขึ้น สำหรับถั่วอื่น ๆ สปริงได้นำคำแนะนำของผู้เขียนและทำให้การฉีด 'SecurityContextHolder' ง่ายขึ้น รายละเอียดเพิ่มเติมอยู่ในความคิดเห็น
นี่คือทางออกที่ฉันได้ไปด้วย แทนที่จะใช้SecurityContextHolder
ในตัวควบคุมของฉันฉันต้องการฉีดสิ่งที่ใช้SecurityContextHolder
ภายใต้ประทุน ฉันไม่พบวิธีที่จะทำสิ่งนี้นอกจากใช้งานอินเทอร์เฟซของฉันเอง:
public interface SecurityContextFacade {
SecurityContext getContext();
void setContext(SecurityContext securityContext);
}
ตอนนี้ผู้ควบคุมของฉัน (หรืออะไรก็ตามที่ POJO) จะมีลักษณะเช่นนี้:
public class FooController {
private final SecurityContextFacade securityContextFacade;
public FooController(SecurityContextFacade securityContextFacade) {
this.securityContextFacade = securityContextFacade;
}
public void doSomething(){
SecurityContext context = securityContextFacade.getContext();
// do something w/ context
}
}
และเนื่องจากอินเทอร์เฟซเป็นจุดแยกการทดสอบจึงตรงไปตรงมา ในตัวอย่างนี้ฉันใช้ Mockito:
public class FooControllerTest {
private FooController controller;
private SecurityContextFacade mockSecurityContextFacade;
private SecurityContext mockSecurityContext;
@Before
public void setUp() throws Exception {
mockSecurityContextFacade = mock(SecurityContextFacade.class);
mockSecurityContext = mock(SecurityContext.class);
stub(mockSecurityContextFacade.getContext()).toReturn(mockSecurityContext);
controller = new FooController(mockSecurityContextFacade);
}
@Test
public void testDoSomething() {
controller.doSomething();
verify(mockSecurityContextFacade).getContext();
}
}
การใช้งานเริ่มต้นของอินเทอร์เฟซมีลักษณะดังนี้:
public class SecurityContextHolderFacade implements SecurityContextFacade {
public SecurityContext getContext() {
return SecurityContextHolder.getContext();
}
public void setContext(SecurityContext securityContext) {
SecurityContextHolder.setContext(securityContext);
}
}
และในที่สุดการกำหนดค่าการผลิตฤดูใบไม้ผลิมีลักษณะเช่นนี้:
<bean id="myController" class="com.foo.FooController">
...
<constructor-arg index="1">
<bean class="com.foo.SecurityContextHolderFacade">
</constructor-arg>
</bean>
ดูเหมือนว่าโง่ไปกว่านั้นที่สปริงซึ่งเป็นภาชนะฉีดของทุกสิ่งไม่ได้ให้วิธีการฉีดสิ่งที่คล้ายกัน ฉันเข้าใจว่าSecurityContextHolder
สืบทอดมาจาก acegi แต่ถึงกระนั้น สิ่งคือพวกเขาอยู่ใกล้ - ถ้าSecurityContextHolder
มีเพียงทะเยอทะยานที่จะได้รับSecurityContextHolderStrategy
อินสแตนซ์พื้นฐาน(ซึ่งเป็นอินเทอร์เฟซ) คุณสามารถฉีดที่ ในความเป็นจริงฉันยังเปิดปัญหาจิรากับผลกระทบนั้น
สิ่งหนึ่งที่สุดท้าย - ฉันเพิ่งเปลี่ยนคำตอบที่ฉันเคยมีที่นี่มาก่อน ตรวจสอบประวัติถ้าคุณอยากรู้ แต่ในฐานะเพื่อนร่วมงานชี้ให้ฉันคำตอบก่อนหน้าของฉันจะไม่ทำงานในสภาพแวดล้อมแบบมัลติเธรด ที่อยู่ภายใต้SecurityContextHolderStrategy
การใช้งานโดยSecurityContextHolder
มีค่าเริ่มต้นเป็นตัวอย่างของThreadLocalSecurityContextHolderStrategy
ที่ร้านค้าSecurityContext
s ThreadLocal
ใน ดังนั้นจึงไม่ใช่ความคิดที่ดีที่จะฉีดSecurityContext
เข้าไปใน bean โดยตรงในเวลาเริ่มต้น - อาจจำเป็นต้องดึงข้อมูลจากThreadLocal
แต่ละครั้งในสภาพแวดล้อมแบบมัลติเธรดดังนั้นจึงเรียกข้อมูลที่ถูกต้องได้