ERRORHiSTORY

JWT 인증과 권한 처리 중 403 Forbidden 오류 해결 사례

jki09871 2024. 9. 11. 02:29
JWT(JSON Web Token) 인증을 사용하는 애플리케이션에서 Spring Security로 보안 처리를 하던 중 403 Forbidden 오류가 발생했다. 이 오류는 사용자 인증은 성공했지만, 권한(authorization)이 부족해서 발생하는 문제이다. 이 글에서는 실제로 발생했던 403 Forbidden 오류의 원인과 해결 과정을 설명한다.

문제 상황

Spring Boot와 Spring Security를 사용해 JWT 인증 기반 보안 시스템을 구축한 후, ADMIN 권한을 가진 사용자가 /admin 경로에 접근할 때 403 Forbidden 오류가 발생했다. 로그를 확인한 결과, JWT 토큰은 정상적으로 처리되고 있었지만, 여전히 403 Forbidden 상태가 반환되고 있었다. 이는 인증은 성공했으나, 권한이 부족해서 발생한 문제였다.


원인 분석

이 문제의 원인은 Spring Security의 권한 관리 방식과 JWT 토큰에서 역할 정보의 불일치였다. 구체적으로는 다음 두 가지 원인이 있었다.

1. JWT 토큰의 역할 정보와 Spring Security 권한 설정의 불일치

Spring Security는 권한을 설정할 때, 역할에 ROLE_ 접두사를 사용한다. 즉, ADMIN 역할은 ROLE_ADMIN으로 인식되어야 한다. 하지만 JWT 토큰의 role 필드는 단순히 ADMIN으로 저장되고 있었다. 이로 인해 Spring Security는 해당 사용자의 권한을 제대로 인식하지 못하고, 403 Forbidden을 반환한 것이다.

2. CustomUserDetails 클래스에서 권한 설정 오류

CustomUserDetails 클래스에서는 사용자 권한을 반환할 때 GrantedAuthority를 사용한다. 그러나 이 클래스에서 ROLE_ 접두사가 누락된 권한 정보가 반환되어 Spring Security에서 올바르게 처리되지 않았다.


해결 방법

이 문제를 해결하기 위해 두 가지 작업을 진행했다.

1. JWT 토큰 생성 시 ROLE_ 접두사 추가

JWT 토큰에 역할 정보를 저장할 때, ROLE_ 접두사를 추가해 Spring Security가 요구하는 형식으로 맞췄다. 이를 통해 Spring Security는 ADMIN 역할을 가진 사용자를 ROLE_ADMIN으로 인식하게 된다.

public String createJwt(String username, String role, Long expiredMs) {
    return Jwts.builder()
            .claim("username", username)
            .claim("role", "ROLE_" + role)  // ROLE_ 접두사 추가
            .issuedAt(new Date(System.currentTimeMillis()))
            .expiration(new Date(System.currentTimeMillis() + expiredMs))
            .signWith(secretKey)
            .compact();
}

2. CustomUserDetails 클래스에서 권한 정보 수정

CustomUserDetails 클래스에서도 역할 정보를 반환할 때 ROLE_ 접두사를 포함하도록 수정했다.

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    Collection<GrantedAuthority> authorities = new ArrayList<>();
    authorities.add(new SimpleGrantedAuthority("ROLE_" + userEntity.getRole()));  // ROLE_ 접두사 추가
    return authorities;
}

해결 결과

이 두 가지 문제를 수정한 후, /admin 경로에 접근할 때 더 이상 403 Forbidden 오류가 발생하지 않고, 권한이 부여된 사용자는 정상적으로 접근할 수 있었다.

결론

JWT 토큰과 Spring Security를 함께 사용할 때, 역할 정보의 일치 여부는 매우 중요하다. Spring Security는 기본적으로 ROLE_ 접두사가 요구되기 때문에, 이를 토큰 생성 및 권한 처리 시 정확히 반영해야 한다. 이와 같은 문제가 발생하지 않도록 설계 단계에서 역할 정보를 명확하게 처리하는 것이 중요하다.

이렇게 문제를 해결함으로써 403 Forbidden 오류를 해결할 수 있었다.