본문 바로가기
Spring Security

[Spring Security] 인증(Authentication), 인가(Authorization), 권한(Authority), 역할(Role) 알아보기

by 코더 제이콥 2023. 6. 19.

1. 인증과 인가

인증은 시스템에 접근하기 위해 회원의 정보를 확인하는 것입니다. 인증은 인가 이전에 완료되며, 보통 회원의 로그인 정보가 필요합니다. 만약 인증이 실패한다면, 클라이언트는 401 UNAUTHORIZED 에러를 응답받습니다.

인가란 특정 리소스에 접근하려는 회원의 권한을 확인하는 것입니다. 인가는 항상 인증 이후에 일어나며, 회원의 권한(privilege)이나 역할(role)이 필요합니다. 만약 인가가 실패한다면, 클라이언트는 403 FORBIDDEN 에러를 응답받습니다.

정리

  • 인증은 인가 전에 완료된다.
  • 인증이 실패하면 401 UNAUTHORIZED 에러를 응답받는다.
  • 인가는 리소스에 접근하려는 회원의 권한을 확인하는 것이다. 예를 들어 본인이 작성한 게시글이 아닌데 삭제하려고 할 때이다.
  • 인가가 실패하면 403 FORBIDDEN 에러를 응답받는다.

2. 권한(Authority)들은 어떻게 저장될까?

스프링 시큐리티에서 권한들과 역할은 기본적으로 GrantedAuthority에 저장됩니다. GrantedAuthority는 권한이나 역할의 이름을 반환하는 메소드를 제공합니다.

public interface GrantedAuthority extends Serializable {

    String getAuthority();

}

SimpleGrantedAuthority 클래스는 GrantedAuthority 인터페이스의 기본으로 구현되는 객체입니다.

public final class SimpleGrantedAuthority implements GrantedAuthority {

    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

    private final String role;

    public SimpleGrantedAuthority(String role) {
        Assert.hasText(role, "A granted authority textual representation is required");
        this.role = role;
    }

    @Override
    public String getAuthority() {
        return this.role;
    }

    ...
}

3. 권한(Authority)와 역할(Role)의 차이점

권한과 역할의 차이점은 접근 권한을 얼마나 쪼개는 가에 있다.

접근 권한을 개별의 특정 행위로 규정할 때 Authority를 사용합니다. 접근 권한을 특정 집단으로 규정할 때 Role을 사용합니다. 쉽게 말해, 접근 권한을 짧게 쪼갤 때 Authority를 사용하며, 길게 쪼갤 때 Role을 사용합니다.

예를 들어 쇼핑몰 사이트가 있을 때 구매 권한, 판매 권한, 좋아요 권한 등 짧게 쪼갤 때 Authority를 사용합니다. 반면, 관리자, 구매자, 판매자와 같이 특정 집단으로 묶어 관리할 때에는 Role을 사용합니다.

접근 권한을 일일히 지정하는 것은 번거롭기 때문에 주로 역할을 사용합니다. 여기서 데이터베이스에 회원의 역할을 정의할 때 유의할 사항이 있습니다. 역할을 정의할 때에는 접두사로 ROLE_로 시작해야 합니다. 가령 ROLE_USER, ROLE_VENDER, ROLE_ADMIN를 예로 들 수 있습니다.

/**
 * Specifies a user requires a role.
 * @param role the role that should be required which is prepended with ROLE_
 * automatically (i.e. USER, ADMIN, etc). It should not start with ROLE_
 * @return {@link AuthorizationManagerRequestMatcherRegistry} for further
 * customizations
 */
public AuthorizationManagerRequestMatcherRegistry hasRole(String role) {
   return access(withRoleHierarchy(AuthorityAuthorizationManager.hasRole(role)));
}

데이터베이스에 역할을 저장할 때, ROLE_로 시작해야 합니다. 하지만, 주석을 보시면 2 - 3 번째 줄에서 ROLE_ 접두사는 자동으로 붙기 때문에 파라미터에 역할만 넣으라고 되어 있습니다.

그리고 구성 정보를 설정해서 역할에 따라 들어갈 수 있는 URL들을 설정할 수 있습니다. 역할 설정에는 hasRole(), hasAnyRole() 메소드가 있습니다.설정을 보겠습니다.

.authorizeHttpRequests((requests) -> requests
    .requestMatchers("/myShop").hasRole("VENDOR")
    .requestMatchers("/myHOME").hasAnyRole("USER", "ADMIN")
    .requestMatchers("/myCart").hasRole("USER")
    .requestMatchers("/myShop", "/myHome", "/myCart").authenticated()
    .requestMatchers("/register").permitAll())

이렇게 메소드의 파라미터로 ROLE_역할이 아닌, 역할만 넣는다면 자동으로 ROLE_역할로 인식합니다.