Spring Security’yle entegre çalışan bir uygulamada, kullanıcıların oturumlarına yönelik bilgiler SecurityContext
nesnelerinde tutuluyor. SecurityContext
nesneleri ise SecurityContextHolder
içerisinde tutuluyor.
Varsayılan olarak SecurityContextHolder
, SecurityContext
nesnelerini ThreadLocal
kullanarak saklıyor. Böylelikle aynı thread’de çalışan metodlar aynı SecurityContext
nesnesine ulaşabiliyorlar. SecurityContextHolder
in çalışma modu da istenildiği takdirde değiştirilebiliyor.
Uygulamanın oturumla alakalı işlerini Spring Security halletse de, bazen oturum açan kullanıcıya yönelik bilgiler bize de gerekebiliyor. Bunun için öncelikle SecurityContext
nesnesine ulaşmamız gerekiyor. Onu da şöyle yapabiliyoruz.
SecurityContext securityContext = SecurityContextHolder.getContext();
Bu çağrıyla elde ettiğimiz securityContext
üzerinden Authentication
ve UserPrincipal
a erişebiliyoruz. Fakat bu kullanım şuradaki abimin dediği gibi test edilebilirliği bozuyor. Bunun için bu çağrıyı gizlemek daha uygun bir yaklaşım.
public class SecurityContextUtils {
public SecurityContext getSecurityContext() {
return SecurityContext.getContext();
}
}
SecurityContextUtils
sınıfının içine UserPrincipal
veya username
i de getiren metodlar yazılabilir. Bu yöntemle statik metod çağrısını, normal bir metodun içerisine gizledik ve SecurityContextUtils
i ve SecurityContext
i mocklayabilir hale geldik.
Uygulamada Spring de kullanıyorsak şöyle bir sınıf da yazabiliriz.
@Component
public class SecurityContextUtils {
private SecurityContextHolderStrategy securityContextHolderStrategy;
@PostConstruct
void init() {
securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
}
public SecurityContext getSecurityContext() {
return securityContextHolderStrategy.getContext();
}
}
SecurityContext
nesneleri HTTP request’leri boyunca ThreadLocal
de tutuluyor. Request sonlanınca, ilgili SecurityContext ThreadLocal
den silinip bir sonra request’te tekrar ThreadLocal
e alınıyor. Bunun sebebi ise request’in sonlandığı thread’in, servlet container’in thread pool’una alınıp başka bir request’i ele alması ihtimali. Eski SecurityContext
ThreadLocal
den silinmezse thread’de çalışan yeni request yanlış SecurityContext
nesnesine erişir. Bu durumu düşünmemiş olmamdan dolayı, ben bir hatayla karşılaştım; onu da yazmak istiyorum. Spring Security filtrelerini kapattığım bir URL’e sahip sayfada, SecurityContext
e erişmeye çalıştım. Filtreler kapalı olduğundan SecurityContext
nesnesine ThreadLocal
e alınmıyordu ve erişmeye çalıştığımda null dönüyordu. Buna dikkat etmek gerekiyor.