uncategorized

Spring Security - SecurityContextRepository

SecurityContextRepository

SecurityContextRepository 는 SecurityContext 를 저장하고 검색하기 위한 저장소입니다.

Spring Security 에서는 인증 후 생성된 SecurityContext 를 저장하고 관리하기 위해 SecurityContextRepository 인터페이스를 제공합니다.

public interface SecurityContextRepository {
@Deprecated
SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder);

default DeferredSecurityContext loadDeferredContext(HttpServletRequest request) {
Supplier<SecurityContext> supplier = () -> loadContext(new HttpRequestResponseHolder(request, null));
return new SupplierDeferredSecurityContext(SingletonSupplier.of(supplier),
SecurityContextHolder.getContextHolderStrategy());
}

// 변경된 보안 컨텍스트를 저장합니다. 주로 사용자가 인증되면 새로운 보안 컨텍스트를 저장하는 데 사용됩니다.
void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response);

// 현재 요청에서 보안 컨텍스트가 존재하는지 확인합니다.
boolean containsContext(HttpServletRequest request);
}

Session 에 저장 - HttpSessionSecurityContextRepository

HttpSessionSecurityContextRepository 는 Session 에 SecurityContext 정보를 저장합니다.

@Override
public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
SaveContextOnUpdateOrErrorResponseWrapper responseWrapper = WebUtils.getNativeResponse(response,
SaveContextOnUpdateOrErrorResponseWrapper.class);
if (responseWrapper == null) {
saveContextInHttpSession(context, request);
return;
}
responseWrapper.saveContext(context);
}

private void saveContextInHttpSession(SecurityContext context, HttpServletRequest request) {
if (isTransient(context) || isTransient(context.getAuthentication())) {
return;
}
SecurityContext emptyContext = generateNewContext();
if (emptyContext.equals(context)) {
HttpSession session = request.getSession(false);
removeContextFromSession(context, session);
}
else {
boolean createSession = this.allowSessionCreation;
HttpSession session = request.getSession(createSession);
setContextInSession(context, session);
}
}

Request 객체에 저장 - RequestAttributeSecurityContextRepository

RequestAttributeSecurityContextRepository 는 Request 객체에 SecurityContext 정보를 저장하는 객체입니다.

RequestAttributeSecurityContextRepository 는 요청 정보에 SecurityContext 를 저장하기 때문에 요청이 끝나게 되면 SecurityContext 정보도 같이 사라지게 됩니다.

@Override
public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
request.setAttribute(this.requestAttributeName, context);
}

여러개의 Request 객체에 저장 - DelegatingSecurityContextRepository

여러개의 SecurityContextRepository 를 사용하기 위해 Spring Security 에서는 DelegatingSecurityContextRepository 를 제공합니다. 다음과 같이 여러개의 SecurityContextRepository 객체를 인자로 해 DelegatingSecurityContextRepository 객체를 생성할 수 있습니다.

@Bean
public SecurityContextRepository securityContextRepository() {
return new DelegatingSecurityContextRepository(
new RequestAttributeSecurityContextRepository(),
new HttpSessionSecurityContextRepository()
);
}

DelegatingSecurityContextRepository 또한 같은 SecurityContextRepository 인터페이스를 통해 생성된 구현체라 사용하는 방식의 차이는 없습니다. 다만, 내부적으로 여러개의 SecurityContextRepository 를 한번씩 실행시키는 방식으로 로직을 수행합니다.

@Override
public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
SecurityContext result = null;
for (SecurityContextRepository delegate : this.delegates) {
SecurityContext delegateResult = delegate.loadContext(requestResponseHolder);
if (result == null || delegate.containsContext(requestResponseHolder.getRequest())) {
result = delegateResult;
}
}
return result;
}
Share