인가 처리
인가 -> 권한을 부여 특정 사용자만 특정 작업을 할 수 있게 함
인가 처리는 두 개의 작업으로 구분
- 인증된 사용자와 권한을 매핑해야 함
- 예시) ROLE_USER, ROLE_ADMIN, ROLE_ANONYMOUS
- 보호되는 리소스에 대한 권한 확인
- 관리자 권한을 가진 사용자만 관리자 페이지에 접근 가능
FilterSecurityInterceptor
필터 체인 상에서 가장 마지막에 위치하며, 사용자가 갖고 있는 권한과 리소스에서 요구하는 권한을 취합하여 접근을 허용할지 결정함실질적으로 접근 허용 여부 판단은 AccessDecisionManager 인터페이스 구현체에서 이루어짐
해당 필터가 호출되는 시점에서 사용자는 이미 AccessDecisionManager에서 인증이 완료된 상태며, Authentication 인터페이스의 getAuthorities() 메소드를 통해 인증된 사용자의 권한 목록을 가져올수 있음익명 사용자도 인증이 완료된 것으로 간주하며, ROLE_ANONYMOUS 권한을 갖음
AccessDecisionManager
사용자가 갖고 있는 권한과 리소스에서 요구하는 권한을 확인하고, 사용자가 적절한 권한을 갖고 있지 않다면 접근 거부 처리함AccessDecisionVoter 목록을 갖고 있으며 AccessDecisionManager의 구현체를 통해 접근 승인 여부를 결정AccessDecisionVoter들의 투표(vote)결과를 취합하고, 접근 승인 여부를 결정하는 3가지 구현체를 제공함자세한 내요은 해당 클래스 내에 메소드를 확인하면 흐름을 이해할 수 있음
AuthorizationFilter
- Spring Security 버전이 6.1로 올라감에 따라 새롭게 간소화된 FilterSecurityInterceptor와 AccessDecisionManager가 아닌 AuthorizationManager API와 AuthorizationFilter를 사용한다.
- 마찬가지로 필터 체인 상에서 가장 마지막에 위치하며, FilterSecurityInterceptor와 역할은 동일하다.
AuthenticationManager
- AccessDecisionManager와는 비교도 안되게 적용 방법이 간단하다.
- 커스텀해서 인증을 필터링 하고 싶다면 AuthenticationManager의 구현체 중 하나인 WebExpressionAuthorizationManager의 코드를 보면 쉽게 작성 가능하다.
- 권한을 계층적으로 적용 가능하다.
권한 계층 AuthenticationManager에 적용한 코드
.requestMatchers(antMatcher("/me")).access(new HierarchyBasedAuthorizationManager(roleHierarchy())) // 커스텀한 AuthenticationManager를 이런식으로 적용 가능
@Bean
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
return roleHierarchy;
}/*
계층형 권한 설정 스프링 시큐리티 버전 6.0에 추가된 내용.
계층형 권한 설정을 통해 ROLE_ADMIN이 ROLE_USER보다 상위 권한이라는 것을 설정함.
*/
static class HierarchyBasedAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
private final RoleHierarchy roleHierarchy;
public HierarchyBasedAuthorizationManager(RoleHierarchy roleHierarchy) {
this.roleHierarchy = roleHierarchy;
}
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
var userAuthorities = authentication.get().getAuthorities();
var reachableAuthorities = roleHierarchy.getReachableGrantedAuthorities(userAuthorities);
var hasUserRole = reachableAuthorities.stream()
.anyMatch(auth -> "ROLE_USER".equals(auth.getAuthority()));
return new AuthorizationDecision(hasUserRole);
}
}
아이디의 마지막 숫자가 짝수인 경우만 승인 접근 권한이 있도록 설정한 AuthenticationManager
.requestMatchers(antMatcher("/admin")).access(allOf(hasRole("ADMIN"), fullyAuthenticated(), new CustomAuthorizationManager())) // 이런식으로 여러개의 AuthenticationManager 설정 가능
static class CustomAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
private static final Pattern PATTERN = Pattern.compile("[0-9]+$");
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
var user = (User) authentication.get().getPrincipal();
var userName = user.getUsername();
var matcher = PATTERN.matcher(userName);
if (matcher.find()) {
var num = Integer.parseInt(matcher.group());
if (num % 2 == 0) {
return new AuthorizationDecision(true);
}
}
return new AuthorizationDecision(false);
}
}
'Spring > Security' 카테고리의 다른 글
Spring Security 7: 데이터베이스를 이용해 인증하기(JDBC) #1 (0) | 2023.08.11 |
---|---|
Spring Security 6: Thread Local (0) | 2023.08.11 |
Spring Security 5: Security Filter #4 (0) | 2023.08.11 |
Spring Security 3: SecurityFilter #2 (0) | 2023.08.08 |
Spring Security 2: SecurityFilter #1 (0) | 2023.08.08 |