발급받은 액세스 토큰은 DB에 저장해서 정보를 요청할 때 가져오도록 했고, 이 과정에서 토큰의 유효성 검사를 한 뒤 만료된 토큰이면 재발급받아 DB에 업데이트하고 새로 받은 토큰으로 정보를 가져오도록 만들었다.
스트리머 정보 가져오기
public Streamer getStreamerInfo(String login) {
// 토큰이 유효하지 않다면 재발급
String token = getAccessToken();
if (!isAccessTokenValid(token)) {
token = reGetAccessToken();
}
// 정보 요청
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(token);
headers.set("Client-Id", clientId);
HttpEntity<?> httpEntity = new HttpEntity<>(headers);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("https://api.twitch.tv/helix/users")
.queryParam("login", login);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<LinkedHashMap> response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, httpEntity, LinkedHashMap.class);
LinkedHashMap data = response.getBody();
ArrayList list = (ArrayList) data.get("data");
LinkedHashMap info = (LinkedHashMap) list.get(0);
Streamer streamer = new Streamer(info);
return streamer;
}
유저 정보를 가져오기 위해서는 액세스 토큰과, 클라이언트 id를 헤더에 담아서 GET 요청을 보내야 한다. HttpHeaders를 통해 쉽게 헤더에 정보를 담을 수 있다. HttpHeaders에는 여러 정보를 담을 수 있도록 메서드를 제공하는 데 기본적으로 제공하는 메서드를 통해 보내고자 하는 정보를 담을 수 없다면, set()을 통해 직접 정해줘야 한다.
RestTemplate을 통해 간단하게 HTTP 요청을 생성하고, 서버로부터의 응답을 처리할 수 있다. HTTP GET, POST, PUT, DELETE 등 다양한 HTTP 메서드를 지원하며, 요청과 응답 데이터를 JSON, XML 등 다양한 데이터 타입으로 변환할 수 있다.
응답받은 것을 LinkedHashMap으로 변환하고, 다시 data라는 속성명으로 꺼내서 ArrayLIst로 변환하고, 거기서 다시 0번째 인덱스를 꺼내 LinkedHashMap으로 변환하고 최종적으로 Streamer 클래스로 담은 것은 요청한 데이터가 이렇게 들어왔기 때문이다.
테스트 코드로 .getClass()를 사용해 자료형을 알아내고 계속 변환해서 Streamer 클래스에 정보를 담았다.
HttpEntity는 HTTP 요청 또는 응답에 해당하는 header와 body를 포함하는 클래스로, RestTemplate과 함께 자주 사용된다.
HttpEntity (Spring Framework 6.0.8 API)
hasBody public boolean hasBody() Indicates whether this entity has a body.
docs.spring.io
https://dev.twitch.tv/docs/api/reference/#get-users
Reference
Twitch Developer tools and services to integrate Twitch into your development or create interactive experience on twitch.tv.
dev.twitch.tv
토큰 가져오기
@Transactional
public String getAccessToken() {
Token token = tokenRepository.findById(1).orElseThrow(() -> new IllegalArgumentException("AccessToken이 없습니다."));
String value = token.getToken();
return value;
}
@Transacional
- 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋한다. 만약 런타임 예외가 발생하면 롤백한다.
- JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다
토큰 유효성 검사
public boolean isAccessTokenValid(String accessToken) {
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
HttpEntity<?> entity = new HttpEntity<>(headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(
"https://id.twitch.tv/oauth2/validate",
HttpMethod.GET,
entity,
String.class);
return response.getStatusCode() == HttpStatus.OK;
}
https://dev.twitch.tv/docs/authentication/validate-tokens/
Validating Tokens
Validating Tokens
dev.twitch.tv
토큰 재발급
@Transactional
public String reGetAccessToken() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<?> entity = new HttpEntity<>(headers);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("https://id.twitch.tv/oauth2/token")
.queryParam("client_id", clientId)
.queryParam("client_secret", clientSecret)
.queryParam("grant_type", "client_credentials");
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<AccessTokenResponse> response = restTemplate.exchange(builder.toUriString(), HttpMethod.POST, entity, AccessTokenResponse.class);
String newToken = response.getBody().getAccess_token();
// 재발급 받은 토큰 update
Token tokenEntity = tokenRepository.findById(1).orElseThrow(() -> new IllegalArgumentException("토큰이 없습니다"));
tokenEntity.update(newToken);
return newToken;
}
참고로 발급받은 토큰 정보와 응답받은 스트리머 정보를 담기 위한 클래스는 아래와 같이 생성했다.
package com.ewok.twitchmeme.dto;
import lombok.Getter;
@Getter
public class AccessTokenResponse {
private String access_token;
private String token_type;
private int expires_in;
}
package com.ewok.twitchmeme.dto.twitch;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.io.Serializable;
import java.util.LinkedHashMap;
@RequiredArgsConstructor
@Getter
public class Streamer implements Serializable {
private String id;
private String login;
private String display_name;
private String type;
private String broadcaster_type;
private String description;
private String profile_image_url;
private String offline_image_url;
private int view_count;
private String created_at;
public Streamer(LinkedHashMap info) {
this.id = (String) info.get("id");
this.login = (String) info.get("login");
this.display_name = (String) info.get("display_name");
this.type = (String) info.get("type");
this.broadcaster_type = (String) info.get("broadcaster_type");
this.description = (String) info.get("description");
this.profile_image_url = (String) info.get("profile_image_url");
this.offline_image_url = (String) info.get("offline_image_url");
this.view_count = (int) info.get("view_count");
this.created_at = (String) info.get("created_at");
}
}
'SpringBoot > 개인프로젝트' 카테고리의 다른 글
Summernote 적용 (0) | 2023.05.01 |
---|---|
트위치 OAuth 로그인 (0) | 2023.05.01 |
트위치 API 스트림 정보 가져오기 (0) | 2023.05.01 |
트위치 API (0) | 2023.05.01 |
프로젝트 생성 (0) | 2023.05.01 |