24.08.29

윤지현·2024년 8월 29일

TIL

목록 보기
53/75

오늘의 루틴

  • 개인과제 9~10단계 시도 및 완료(O)
  • 공부한 내용 복습 (O)

마지막으로 9단계와 10단계를 도전했다.

  • 9단계 : 권한 확인

🔻 조건

  • 유저에 권한을 추가합니다.
    • 권한은 관리자, 일반 사용자 두 가지가 존재합니다.
    • JWT를 발급할 때 유저의 권한 정보를 함께 넣어줍니다.
  • 일정 수정 및 삭제는 관리자 권한이 있는 유저만 할 수 있습니다.

⚠️ 예외 처리

  • 권한이 없는 유저의 경우 403을 반환합니다.

Jwt를 생성하면서도 권한도 같이 넣을 수 있으면서도, 그러한 권한을 선택할 열거형 UserRoleEnum을 생성한다.


1. UserRoleEnum.java

권한은 사용자, 관리자로 총 2개 지정

public enum UserRoleEnum {
    USER(Authority.USER),  // 사용자 권한
    ADMIN(Authority.ADMIN);  // 관리자 권한

    private final String authority;

    UserRoleEnum(String authority) {
        this.authority = authority;
    }

    public String getAuthority() {
        return this.authority;
    }

    public static class Authority {
        public static final String USER = "ROLE_USER";
        public static final String ADMIN = "ROLE_ADMIN";
    }
}

이러한 권한이 있는 컬럼을 만들기 위해 User에 권한 필드를 추가하고, UserRequestDto에도 추가한다. 또한 UserService에서도 유저 생성할 때 사용자 권한도 확인한다.


1. User.java

권한 필드를 추가한다.

    @Column(nullable = false)
    @Enumerated(value = EnumType.STRING)
    private UserRoleEnum role;

User 클래스 생성자를 만들때 권한도 넣는다.

   public User(String username, String email, String password, UserRoleEnum role) {
        this.username = username;
        this.email = email;
        this.password = password;
        this.role = role;
    }

2. UserRequestDto.java

사용자 요청 데이터를 전달할 때 권한과 관리자 키도 포함한다.

@Getter
@Setter
public class UserRequestDto {
    private String username;
    private String password;
    private String email;
    private boolean admin = false;
    private String adminToken = "";
}

3. UserService.java

입력받은 사용자 권한을 확인

        // 사용자 ROLE 확인
        UserRoleEnum role = UserRoleEnum.USER;  // 기본값: USER
        if (userRequestDto.isAdmin()) {
            if (!ADMIN_TOKEN.equals(userRequestDto.getAdminToken())) {
                throw new IllegalArgumentException("관리자 암호가 틀려 등록이 불가능합니다.");
            }
            role = UserRoleEnum.ADMIN;
        }

JWT를 생성할 때 권한도 함께

// JWT 생성
        String token = jwtUtil.createToken(user.getUsername(), role);

jwt를 생성할 때 권한도 함께 넣은 JwtUtil과 AuthFilter도 수정 및 추가


1. JwtUtil.java

token을 생성할 때 권한도 추가

    public String createToken(String username, UserRoleEnum role) {
        Date date = new Date();

        return BEARER_PREFIX +
                Jwts.builder()
                        .setSubject(username)
                        .claim(AUTHORIZATION_KEY, role.getAuthority()) // 사용자 권한
                        .setExpiration(new Date(date.getTime() + TOKEN_TIME))
                        .setIssuedAt(date)
                        .signWith(key, signatureAlgorithm)
                        .compact();
    }

2. AuthFilter.java

'HttpServletRequest'로 변환한 request에 나중에 권한을 확인하기 위해 해당 값을 저장

request.setAttribute("role", info.get(JwtUtil.AUTHORIZATION_KEY));

유저, 댓글, 할일 등의 CRUD을 하면서 권한도 확인한다.(TodoController, UserController, CommentController)


1. 사용자 권한 또는 관리자 권한 둘 다 필요할 경우

        String role = (String) httpServletRequest.getAttribute("role");
        if (role == null || (!UserRoleEnum.USER.getAuthority().equals(role) && !UserRoleEnum.ADMIN.getAuthority().equals(role))) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }

2. 관리자 권한만 필요할 경우

        String role = (String) httpServletRequest.getAttribute("role");
        if (role == null || !UserRoleEnum.ADMIN.getAuthority().equals(role)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }

9단계도 잘 실행이 된다. 이제는 10단계를 할 것이다.

  • 10단계 : 외부 API 조회

🔻 조건

  • 날씨 정보 데이터 API를 활용하여 오늘의 날씨를 조회할 수 있습니다.
    • RestTemplate을 사용해 날씨를 조회합니다.
  • 일정에 날씨 필드를 추가합니다.
    • 일정 생성 시에 날씨 정보를 생성일 기준으로 저장할 수 있습니다.


외부 API를 조회할 WeatherApIService를 생성한다.


1. WeatherApIService.java

@Slf4j(topic = "Weather API")
@Service
public class WeatherApIService {

    private final RestTemplate restTemplate;

    public WeatherApIService(RestTemplateBuilder builder) {
        this.restTemplate = builder.build();
    }

    public String getWeatherToday() {
        // 요청 URL 만들기
        URI uri = UriComponentsBuilder
                .fromUriString("링크 이름")
                .build()
                .toUri();
        log.info("uri = " + uri);

        ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);

        return fromsontoString(responseEntity.getBody());
    }

    private String fromsontoString(String responseEntity) {
        // 현재 날짜 가져오기
        String todayDate = LocalDate.now().format(DateTimeFormatter.ofPattern("MM-dd"));

        // JSON 응답 처리
        JSONArray weatherArray = new JSONArray(responseEntity);

        for (int i=0; i<weatherArray.length(); i++) {
            JSONObject weatherObject = weatherArray.getJSONObject(i);
            String date = weatherObject.getString("date");
            String weather = weatherObject.getString("weather");

            // 현재 날짜와 일치하는 지 확인
            if (todayDate.equals(date)) {
                return weather;
            }
        }

        return "No weather data about date in Weather API";
    }
}

Todo 엔티티에 날씨 컬럼을 추가하고, TodoResponseDto에 응답 받을 때 날씨를 추가한다.


1. Todo.java

    @Column(name = "weather")
    private String weather;
    
        public Todo(String title, String content, String weather) {
        this.title = title;
        this.content = content;
        this.weather = weather;
    }

2. TodoResponseDto.java

밑에 추가

    private String weather;

    this.weather =  todo.getWeather();

일정을 생성할 때 날씨도 넣기 위해 TodoService에 추가


1. TodoService.java

// 날씨 정보 조회
        String weather = weatherAPIService.getWeatherToday();
        
// RequestDto -> Entity
        Todo todo = new Todo(requestDto.getTitle(), requestDto.getContent(), weather);

날씨 데이터가 저장된다.

profile
첫 시작

0개의 댓글