[추가] AuthorizeRequests vs AuthorizeHttpRequests
목차
- [이론] 스프링 시큐리티 1
- [이론] 스프링 시큐리티2
- [실습] 스프링 시큐리티 Form Login
- [추가] CustomAuthenticationProvider vs DaoAuthenticationProvider
- [이론] 스프링 시큐리티3
- [이론] 스프링 시큐리티4
- [추가] AuthorizeReqeusts vs AuthorizeHttpRequests
- [실습] 스프링 시큐리티 Json data Login 처리
- [실습] 스프링 시큐리티 JWT 설정
- [실습] 스프링 시큐리티 JWT 처리
- OAuth2
서론
이번글에선 Spring Security를 공부하면서 버전업에 의한 변경점에 대해서 다뤄볼 예정이다
기존에는 authorizeRequests를 사용하여 EndPoint에 관한 설정을 했지만 5.6버전 이후(아마도? docs보면 5.6부터 추가된 듯 보이긴 하는데) authorizeHttpRequests를 사용하는 것을 권장하고 있다
단순히 사용만 하는 것에 있어서는 그렇게 큰 차이는 없는 것 같지만 내부에서 동작이 크게 바뀌었기 때문에 한번 정리를 해보기로 한다
AuthorizeRequests
기존에 5.6버전 이전에 사용되는 방식이다
위 사진과 같이 SecurityFilterChain에 FilterSecurityInterceptor라는 필터가 추가된다
1번부터 순차적으로 동작을 보게되면
- SecurityContextHolder로 부터 Authentication객체 받아오기
- HttpServletRequest, HttpServletResponse, FilterChain을 이용하여 FilterInvocation 생성
- SecurityMetadataSource에 FilterInvocation를 전달하여 ConfigAtributes 가져오기
- AccessDecisionManager에 Authentication, FilterInvocation, ConfigAttribute 전달
- 접근 불가일 경우 예외 던짐
- ExceptionTranslationFilter에서 예외 처리
- 접근 가능한 경우 filterChain타고 다음 filter로 전달
너무나도 많은 과정을 거치게 되고 권한이 필요없는 경로에서도 authentication에 관한 정보를 조회를 해야하는 단점이 있다
이러한 많은 과정을 단순화해서 만들어 진것이 authorizeHttpRequests이다
public class AffirmativeBased extends AbstractAccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException {
int deny = 0;
//모든 경로에 대해서 권한을 확인한다
for (AccessDecisionVoter voter : getDecisionVoters()) {
int result = voter.vote(authentication, object, configAttributes);
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
return;
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
break;
}
}
if (deny > 0) {
throw new AccessDeniedException(
this.messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
}
checkAllowIfAllAbstainDecisions();
}
}
AuthorizeHttpRequests
5.6버전 이후 사용시 권장
기존과는 다르게 FilterSecurityInterceptor가 아닌 AuthorizationFilter라느 필터가 추가된다
사진만 봐도 과정이 매우 단순해 진 것을 볼 수 있다
1번부터 순차적으로 동작을 보게되면
- SecurityContextHolder로 부터 Authentication객체 받아오기
- 이 부분에 대해서는 지연조회를 위해 Supplier에 한번 래핑되어 가져오게 된다
- Authorizationmanager에 Supplier-Authentication, HttpServletRequest 전달
- 접근 불가일 경우 예외 던짐
- ExceptionTranslationFilter에서 예외 처리
- 접근 가능한 경우 filterChain타고 다음 filter로 전달
Spring Security Docs를 보게되면 Supplier에 한번 래핑을 함으로써 모든 요청에 대해서 권한이 필요한지를 보는 것이 아닌 권한이 요구되는 곳에서만 확인을 하게 된다고 한다
public final class RequestMatcherDelegatingAuthorizationManager implements AuthorizationManager<HttpServletRequest> {
private final List<RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>>> mappings;
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, HttpServletRequest request) {
for (RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>> mapping : this.mappings) {
RequestMatcher matcher = mapping.getRequestMatcher();
MatchResult matchResult = matcher.matcher(request);
//요청받은 경로가 권한여부를 확인해야하는지 체크
if (matchResult.isMatch()) {
AuthorizationManager<RequestAuthorizationContext> manager = mapping.getEntry();
return manager.check(authentication,
new RequestAuthorizationContext(request, matchResult.getVariables()));
}
}
this.logger.trace("Abstaining since did not find matching RequestMatcher");
return null;
}
}
이러한 것을 모르더라도 추후 나온것이 더 좋다고 Spring을 믿고 사용해도 되지않을까라는 생각이다
지금당장 필요한 것은 아니지만 이런 것까지 굳이라는 생각보다는 동작을 파악하고 보면서 재밌는 시간이었던 것 같다