[Spring Security] - SecurityContextRepository

๋ชฉ์ฐจ

๐Ÿ”Ž SecurityContextRepository

SecurityContextRepository ๋Š” SecurityContext ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œ ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค.

Spring Security ์—์„œ๋Š” ์ธ์ฆ ํ›„ ์ƒ์„ฑ๋œ SecurityContext ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด SecurityContextRepository ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

SecurityContextRepository ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์„ ํ†ตํ•ด ์ธ์ฆ ๊ฐ์ฒด(SecurityContext) ๋ฅผ Request ๊ฐ์ฒด๋‚˜ Session ์— ์ €์žฅํ•˜๊ฑฐ๋‚˜ ์•„๋‹ˆ๋ฉด Redis ์™€ ๊ฐ™์€ ๋ณ„๋„์˜ ์ €์žฅ์†Œ์— ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SecurityContextRepository.java
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);
}

1. Session ์— ์ €์žฅ - HttpSessionSecurityContextRepository

HttpSessionSecurityContextRepository ๋Š” Session ์— SecurityContext ์ •๋ณด๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

HttpSessionSecurityContextRepository ์€ SecurityContext ๋ฅผ HttpSession ์— ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— Session ์ด ์œ ์ง€๋˜๋Š”ํ•œ ํ›„์† ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋”๋ผ๋„ ์ธ์ฆ ์ƒํƒœ๊ฐ€ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

HttpSessionSecurityContextRepository.java
@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);
}
}

2. Request ๊ฐ์ฒด์— ์ €์žฅ - RequestAttributeSecurityContextRepository

RequestAttributeSecurityContextRepository ๋Š” Request ๊ฐ์ฒด์— SecurityContext ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

RequestAttributeSecurityContextRepository ๋Š” ์š”์ฒญ ์ •๋ณด์— SecurityContext ๋ฅผ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์š”์ฒญ์ด ๋๋‚˜๊ฒŒ ๋˜๋ฉด SecurityContext ์ •๋ณด๋„ ๊ฐ™์ด ์‚ฌ๋ผ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

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

3. ์—ฌ๋Ÿฌ๊ฐœ์˜ Request ๊ฐ์ฒด์— ์ €์žฅ - DelegatingSecurityContextRepository

์—ฌ๋Ÿฌ๊ฐœ์˜ SecurityContextRepository ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด Spring Security ์—์„œ๋Š” DelegatingSecurityContextRepository ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—ฌ๋Ÿฌ๊ฐœ์˜ SecurityContextRepository ๊ฐ์ฒด๋ฅผ ์ธ์ž๋กœ ํ•ด DelegatingSecurityContextRepository ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

DelegatingSecurityContextRepository ๋˜ํ•œ ๊ฐ™์€ SecurityContextRepository ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ๊ตฌํ˜„์ฒด๋ผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์˜ ์ฐจ์ด๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ๋‚ด๋ถ€์ ์œผ๋กœ ์—ฌ๋Ÿฌ๊ฐœ์˜ SecurityContextRepository ๋ฅผ ํ•œ๋ฒˆ์”ฉ ์‹คํ–‰์‹œํ‚ค๋Š” ๋ฐฉ์‹์œผ๋กœ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

DelegatingSecurityContextRepository.java
@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