Ensar Basri Kahveci

overly distributed

Spring Security’de SecurityContext'e ulaşmak

Posted at — Jul 26, 2011

java - spring - spring security 

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. SecurityContextHolderin ç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 UserPrincipala 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 usernamei de getiren metodlar yazılabilir. Bu yöntemle statik metod çağrısını, normal bir metodun içerisine gizledik ve SecurityContextUtilsi ve SecurityContexti 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 ThreadLocalde tutuluyor. Request sonlanınca, ilgili SecurityContext ThreadLocalden silinip bir sonra request’te tekrar ThreadLocale 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 ThreadLocalden 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, SecurityContexte erişmeye çalıştım. Filtreler kapalı olduğundan SecurityContext nesnesine ThreadLocale alınmıyordu ve erişmeye çalıştığımda null dönüyordu. Buna dikkat etmek gerekiyor.

comments powered by Disqus