반응형

이 글에서는 RESTful API에 인증과 권한 관리를 적용하는 두 번째 단계를 다룹니다. 이전 단계에서는 JWT 기반의 인증 개념과 간단한 토큰 생성 및 검증 과정을 배웠습니다. 이제 권한 관리를 포함한 보다 심화된 내용을 다룹니다.


1. 권한(Role) 개념 이해하기

API 시스템에서는 사용자 또는 서비스가 어떤 자원을 접근할 수 있는지 제어해야 합니다. 이를 **Role-Based Access Control (RBAC)**이라 하며, 사용자의 역할(Role)에 따라 권한을 부여합니다.

역할(Role)의 예

  • Admin: 모든 자원에 대한 읽기/쓰기/삭제 권한.
  • User: 자신의 데이터에 대한 읽기/쓰기 권한.
  • Guest: 읽기 권한만 허용.

2. 데이터베이스에서 권한 정보 관리

권한 정보를 데이터베이스에 저장하고, 인증 시 이 정보를 확인하여 API 접근을 제어할 수 있습니다.

권한 테이블 설계 예

CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    role VARCHAR(50) NOT NULL
);

샘플 데이터

INSERT INTO users (username, password, role) 
VALUES ('admin', 'hashed_password', 'ADMIN'),
       ('john_doe', 'hashed_password', 'USER'),
       ('guest_user', 'hashed_password', 'GUEST');

3. 권한 검사 Middleware 구현 (Java 예제)

Spring Boot에서 권한 검사 구현

1) 사용자 역할(Role) 포함한 JWT 생성

JWT의 claims에 사용자 역할을 포함합니다.

private String generateToken(User user) {
    return Jwts.builder()
            .setSubject(user.getUsername())
            .claim("role", user.getRole()) // 역할 포함
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 1일
            .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
            .compact();
}

2) 요청 시 권한 검사

JWT에서 역할(Role)을 추출하고, 요청된 API와 비교하여 권한을 확인합니다.

@Component
public class AuthorizationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        String header = request.getHeader("Authorization");
        if (header == null || !header.startsWith("Bearer ")) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Missing or invalid token");
            return;
        }

        try {
            String token = header.substring(7);
            Claims claims = Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();

            String role = claims.get("role", String.class);
            String requestURI = request.getRequestURI();

            if (!isAuthorized(role, requestURI)) {
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                response.getWriter().write("Forbidden: Insufficient permissions");
                return;
            }

            filterChain.doFilter(request, response);

        } catch (Exception e) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Invalid token");
        }
    }

    private boolean isAuthorized(String role, String requestURI) {
        // 간단한 역할 기반 권한 로직
        if (role.equals("ADMIN")) {
            return true; // ADMIN은 모든 경로 허용
        } else if (role.equals("USER") && requestURI.startsWith("/user")) {
            return true; // USER는 /user 경로만 허용
        } else if (role.equals("GUEST") && requestURI.startsWith("/public")) {
            return true; // GUEST는 /public 경로만 허용
        }
        return false;
    }
}

4. 역할(Role)에 따른 API 예제

1) Admin만 접근 가능한 API

@RestController
@RequestMapping("/admin")
public class AdminController {

    @GetMapping("/dashboard")
    public ResponseEntity<String> adminDashboard() {
        return ResponseEntity.ok("Admin Dashboard");
    }
}

2) User 전용 API

@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/profile")
    public ResponseEntity<String> userProfile() {
        return ResponseEntity.ok("User Profile Data");
    }
}

3) Guest 전용 API

@RestController
@RequestMapping("/public")
public class PublicController {

    @GetMapping("/info")
    public ResponseEntity<String> publicInfo() {
        return ResponseEntity.ok("Public Information");
    }
}

5. Postman을 이용한 권한 테스트

  1. JWT 토큰 생성 요청
    • /auth/login 엔드포인트에서 username과 password로 JWT 생성.
  2. API 요청 시 Authorization 헤더 추가
    • Authorization: Bearer <JWT_TOKEN>을 헤더에 포함.
  3. 권한 부족 시 응답 코드 확인
    • 권한 부족 시 403 Forbidden 응답 확인.

6. 권한 관리의 확장

  • 세분화된 권한 체계: 특정 사용자마다 더 세밀한 권한 설정.
  • Scope 추가: OAuth2의 Scope 개념을 활용하여 API 접근 세분화.
  • Policy-Based Access Control (PBAC): JSON이나 YAML로 권한 정책 정의.
반응형

+ Recent posts