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. SecurityContextHolder
Denetleyicimde 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 SecurityContextHolder
temel 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 SecurityContextHolderStrategy
kullanılan SecurityContextHolder
varsayılan, bir örneği gereği, ThreadLocalSecurityContextHolderStrategy
mağazalar SecurityContext
s a ThreadLocal
. Bu nedenle, SecurityContext
baş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.