TIL_0216 - JWT 권한 추가 및 만료 시간 실수

johaS2·2025년 2월 16일

JWT 만료 시간 설정 실수 & 디버깅 과정

  • 문제 발견 과정
    로그인해서 생성된 토큰으로 내 정보 조회 API를 실행하는데 자꾸 403 에러가 발생. 403 에러는 권한 문제라고 해서 권한 관련 코드들만 확인했다.
  • 디버깅을 위한 코드 추가
public boolean validateToken(String token) {
    try {
        Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token);
        return true;
    } catch (Exception e) {
        System.out.println("JWT validation failed: " + e.getMessage());
        return false;
    }
}
  • 디버깅 결과
    콘솔에서 JWT validation failed: Expired JWT 메시지를 확인하고, 만료 시간 설정 실수를 발견.
  • EXPIRATION_TIME이 밀리초 단위인데 3600만 써놔서 3.6초 만에 만료가 되고 있었다..😁 *1000 해줘서 해결

JWT 권한 추가 과정 (Role Enum 사용)

  1. Role Enum 정의 및 엔티티 수정
public enum Role {
    CUSTOMER, OWNER, ADMIN
}

엔티티도 수정

 @Enumerated(EnumType.STRING)
    private Role role;

2.JWT 토큰 생성 시 Role을 claim으로 추가

public String createToken(String email, Role role) {
    String token = Jwts.builder()
            .setSubject(email)
            .claim("role", role)
            .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
            .signWith(getSigningKey(), SignatureAlgorithm.HS256)
            .compact();
    return token;
}
  1. getAuthentication 수정
public Authentication getAuthentication(String token) {
        String email = getUsernameFromToken(token);
        Optional<User> user = userRepository.findByEmail(email);

        if (user.isPresent()) {
            String role = (String) Jwts.parserBuilder()
                    .setSigningKey(getSigningKey())
                    .build()
                    .parseClaimsJws(token)
                    .getBody()
                    .get("role");

            System.out.println("Role from token: " + role);

            // 권한을 GrantedAuthority로 변환
            GrantedAuthority authority = new SimpleGrantedAuthority(role);

            // 인증 객체 생성
            return new UsernamePasswordAuthenticationToken(user.get(), null, List.of(authority));
        }
        return null;
    }
  1. Login 로직 구현
    로그인 시 user.getRole().name()으로 ROLE_ 접두어를 붙여서 토큰에 추가해서 반환
@Override
    public String login(LoginRequestDto loginRequestDto) {
        // 로그인 로직 구현
        User user = userRepository.findByEmail(loginRequestDto.getEmail())
                .orElseThrow(() -> new IllegalArgumentException("Invalid email"));

        if (passwordEncoder.matches(loginRequestDto.getPassword(), user.getPassword())) {
            String role = "ROLE_" + user.getRole().name();
            return jwtUtil.createToken(user.getEmail(), role);
        } else {
            throw new IllegalArgumentException("Invalid password");
        }
    }
  1. SecurityConfig 접근 권한 설정
// 접근 권한 설정
        http.authorizeHttpRequests((authorizeRequests) ->
                authorizeRequests
                        // 인증 없이 접근 가능 경로 (회원가입, 로그인)
                        .requestMatchers("/api/v1/users/**").permitAll()
                        // 권한을 가진 사용자만 접근 가능 경로
                        .requestMatchers("/api/v1/auth/**").hasAnyRole("CUSTOMER", "OWNER")
                        // ADMIN 권한을 가진 사용자만 접근 가능한 경로
                        .requestMatchers("/api/v1/admin/**").hasRole("ADMIN")
                        // 인증 필요한 경로
                        .anyRequest().authenticated());
                        //.anyRequest().permitAll()

권한 추가 부분은 하고나서 찜찜해서 내일 또 다시 확인해보고 더 좋은 방법이 있는지 확인해봐야겠다..

profile
passionate !!

0개의 댓글