Bu soru cevaplandığından beri Bahar dünyasında çok şey değişti. Spring, mevcut kullanıcıyı bir denetleyiciye almayı basitleştirdi. Diğer fasulye için Spring, yazarın önerilerini kabul etti ve 'SecurityContextHolder' enjeksiyonunu basitleştirdi. Daha fazla ayrıntı yorumlarda yer almaktadır.
Sonuçta bu benim çözümüm. SecurityContextHolderDenetleyicimde kullanmak yerine SecurityContextHolder, kaputun altında kullanan ancak o singleton benzeri sınıfı kodumdan soyutlayan bir şey enjekte etmek istiyorum . Bunu kendi arayüzümü yuvarlamak dışında bunu yapmanın bir yolunu bulamadım, şöyle:
public interface SecurityContextFacade {
SecurityContext getContext();
void setContext(SecurityContext securityContext);
}
Şimdi, denetleyicim (veya POJO ne olursa olsun) şöyle görünecektir:
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
}
}
Arayüzün ayrılma noktası olması nedeniyle, birim testi basittir. Bu örnekte Mockito kullanıyorum:
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();
}
}
Arayüzün varsayılan uygulaması şu şekildedir:
public class SecurityContextHolderFacade implements SecurityContextFacade {
public SecurityContext getContext() {
return SecurityContextHolder.getContext();
}
public void setContext(SecurityContext securityContext) {
SecurityContextHolder.setContext(securityContext);
}
}
Ve son olarak, üretim Baharı yapılandırması şöyle görünür:
<bean id="myController" class="com.foo.FooController">
...
<constructor-arg index="1">
<bean class="com.foo.SecurityContextHolderFacade">
</constructor-arg>
</bean>
Her şeyin bağımlılık enjeksiyon kabı olan Spring'in benzer bir şey enjekte etmek için bir yol sağlamadığı biraz aptalca görünüyor. Anlıyorum SecurityContextHolder, acegi'den miras kaldı, ama yine de. Mesele şu ki, çok yakınlar - sadece SecurityContextHoldertemel SecurityContextHolderStrategyörneği (bir arayüz olan) almak için bir alıcı varsa , bunu enjekte edebilirsiniz. Aslında bu konuda bir Jira sorunu bile açtım .
Son bir şey daha önce burada verdiğim cevabı büyük ölçüde değiştirdim. Merak ediyorsanız geçmişi kontrol edin, ancak bir iş arkadaşınızın bana işaret ettiği gibi, önceki cevabım çok iş parçacıklı bir ortamda işe yaramayacaktı. Altta SecurityContextHolderStrategykullanılan SecurityContextHoldervarsayılan, bir örneği gereği, ThreadLocalSecurityContextHolderStrategymağazalar SecurityContexts a ThreadLocal. Bu nedenle, SecurityContextbaşlatma zamanında doğrudan bir fasülyeye enjekte etmek iyi bir fikir değildir - ThreadLocalçok iş parçacıklı bir ortamda her seferinde geri alınması gerekebilir , böylece doğru olanı alınır.