Spring

Security 인가(Authorization) 적용

쭈녁 2024. 3. 16. 23:25

인가 적용 시점

Authentication 객체의

  • Collection<? extends GrantedAuthority> getAuthorities(); 메서드를 구현하면 권한을 담아 둘 수 있다.

 

기타 필드 값

  • detail : User에 대해 담을 정보들의 객체
  • principal : pk 값
  • isAuthenticated : 인증 여부에 대한 참, 거짓 값

 

public interface Authentication extends Principal, Serializable {

    Collection<? extends GrantedAuthority> getAuthorities();

    Object getCredentials();

    Object getDetails();

    Object getPrincipal();

    boolean isAuthenticated();

    void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

 

구현체

@Getter
@Setter
@RequiredArgsConstructor
public class MyTokenAuthentication implements Authentication {
    private final String token;
    
    private MyTokenPayload payload = new MyTokenPayload();
    private boolean authenticated = false;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return payload.getRoles().stream()
                .map(SimpleGrantedAuthority::new)
                .toList();
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    @Override
    public MyTokenPayload getDetails() {
        return payload;
    }

    @Override
    public Long getPrincipal() {
        return payload.getUserId();
    }

    @Override
    public String getName() {
        return payload.getUsername();
    }

}

 

SecurityConfig의 SecurityFilterChain

@Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtFilter jwtFilter) throws Exception {
        return http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(request ->
                        request
                                .requestMatchers(jwtUtil.allowedUrls).permitAll()
                                .requestMatchers("/api/admin/**").hasAuthority("ROLE_GREEN")
//                                .requestMatchers("/api/admin/**").hasAnyRole("GREEN")
                                .anyRequest().authenticated())
                .sessionManagement(sessionManagement ->
                        sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // session을 사용하지 않음
                )
                .addFilterBefore(jwtFilter, RequestCacheAwareFilter.class)
                .build();
    }

 

Autority(권한)와 Role(역할)은 두 가지 다 접근을 막는 역할을 한다. 둘의 차이는 아래와 같다.

 

  • Autority(권한) 은 접근자에 따른 행위를 제한시킬 때 사용한다. 
  • Role(역할)은 User를 역할로 나누어 둔다(예시 관리자, 구매자, 판매자) 이를 기반으로 행위를 제한 시킨다. 역할을 정의할 때에는 접두사로 ROLE_로 시작해야 한다. 

 

접근자에 따른 행위를 제한시키킬때 사용되는 메서드

  • 권한 : hasAuthority(), hasAnyAuthority()
  • 역할 : hasRole(), hasAnyRole()

 

타 블로그등 정리된 글을 참고하였을땐 위 두 메서드 모두 파라미터에 "ROLE_"를 붙이지 않아도 자동으로 붙기에 적지 않아도 된다는 글을 많이 보았다.

 

하지만 필자가 사용하고 있는 SpringSecurity3.2.2 버전에선  hasRole(), hasAnyRole() 메서드는 ROLE_을 생략하고도 작동하였으나  hasAuthority(), hasAnyAuthority() 는 정확한 문자열을 입력해야("ROLE_" 포함) 작동되는 것을 확인하였다.

 

아마 권한과 역할을 동시에 Authority 컬렉션에 저장한 후 위에 설명한 두 메서드의 역할을 구분 지어 사용할 수 있게 함이 아닐까 조심스럽게 추측해 본다.

 

public final class AuthorityAuthorizationManager<T> implements AuthorizationManager<T> {

	private static final String ROLE_PREFIX = "ROLE_";

	public static <T> AuthorityAuthorizationManager<T> hasRole(String role) {
		Assert.notNull(role, "role cannot be null");
		Assert.isTrue(!role.startsWith(ROLE_PREFIX), () -> role + " should not start with " + ROLE_PREFIX + " since "
				+ ROLE_PREFIX + " is automatically prepended when using hasRole. Consider using hasAuthority instead.");
		return hasAuthority(ROLE_PREFIX + role);
	}

        public static <T> AuthorityAuthorizationManager<T> hasAuthority(String authority) {
            Assert.notNull(authority, "authority cannot be null");
            return new AuthorityAuthorizationManager<>(authority);
        }
    
    
    //... 이하 생략
 }

 

 

 

'Spring' 카테고리의 다른 글

공공데이터 Springboot로 파싱  (0) 2024.04.13
Security CORS 설정  (0) 2024.03.17
Mappstruct 사용  (0) 2024.03.11
SpringSecurity 프로젝트 적용  (0) 2024.03.03
SpringSecurity 인증 방식  (0) 2024.03.02