Conversation
release: develop → main
release: develop → main
release: develop → main
release: develop → main
release: develop → main
release: develop → main
release: develop → main
| .queryParam("accessToken", tokenResponse.getAccessToken()) | ||
| .queryParam("refreshToken", tokenResponse.getRefreshToken()) | ||
| .build() |
There was a problem hiding this comment.
URL 쿼리 스트링은 브라우저 히스토리, Nginx access log, 프록시 서버 로그에 기록됩니다. 일회용 authorization code를 발급하고 프론트에서 POST로 교환하는 방식이나, secure HttpOnly 쿠키 방식은 어떻게 생각하시나요?
There was a problem hiding this comment.
넵! httponly 방식을 사용해서 수정하겠습니다
| OAuth2User oauth2User = (OAuth2User) authentication.getPrincipal(); | ||
|
|
||
| String registrationId = oauthToken.getAuthorizedClientRegistrationId(); | ||
| String userNameAttributeName = "sub"; |
There was a problem hiding this comment.
혹시 해당 변수는 어디에서 사용되는걸까요?
There was a problem hiding this comment.
구글 소셜로그인에서는 유저마다 구분하는 키값이 sub 값으로 구분해서 해당 변수를 사용해서 키값으로 지정할 생각이였습니다.
| public class Token { | ||
| @Id @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| private Long id; | ||
|
|
||
| private String tokenId; |
There was a problem hiding this comment.
TokenId를 통해 토큰이 존재하는지 검증할 것 같은데, 혹시 인덱스를 추가하시지 않은 이유가 있을까요?
There was a problem hiding this comment.
앗 hibernate가 자동으로 기본키값을 인덱스로 생성해주는줄 알았는데 아니네요!! 이후에 수정하겠습니다 좋은 정보 감사드려요!
|
|
||
| @Component | ||
| @RequiredArgsConstructor | ||
| public class OAuth2LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { |
There was a problem hiding this comment.
소셜 로그인이 동작하는지 테스트해보셨을까요?
There was a problem hiding this comment.
넵 테스트 했을때 토큰값도 정상적으로 쿼리에 잘 들어가는것까지 확인했습니다.
| LocalDateTime accessExpiresAt = jwtProvider.getClaims(accessToken) | ||
| .getExpiration() | ||
| .toInstant() | ||
| .atZone(ZoneId.systemDefault()) | ||
| .toLocalDateTime(); | ||
|
|
||
| LocalDateTime refreshExpiresAt = jwtProvider.getClaims(refreshToken) | ||
| .getExpiration() | ||
| .toInstant() | ||
| .atZone(ZoneId.systemDefault()) | ||
| .toLocalDateTime(); |
There was a problem hiding this comment.
토큰을 만들고, 다시 파싱해서 만료 시간을 추출하시는 이유가 있을까요? 토큰이 생성될 때, TokenInfo와 같은 값 객체를 활용하면 필요한 정보를 한번에 반환할 수 있어 보여요
There was a problem hiding this comment.
오 넵!! 해당 방법을 사용해서 리팩토링 해보겠습니다
| private SecretKey secretKey; | ||
|
|
||
| @PostConstruct | ||
| public void Init() { // secretkey 값을 읽어 디코딩 하여 바이트 배열로 변환 후 hmac으로 암호화 |
There was a problem hiding this comment.
Java 컨밴션에서는 함수가 소문자로 시작하는데, 혹시 대문자로하신 이유가 있을까요?
| this.secretKey = Keys.hmacShaKeyFor(keyBytes); | ||
| } | ||
|
|
||
| public String createAccesssToken(Long userId, String tokenId) { |
There was a problem hiding this comment.
오타가 있어보여요! createAccesssToken -> createAccessToken
| Token accesTk = Token.builder() | ||
| .tokenId(accessTokenId) | ||
| .user(user) | ||
| .tokenValue(accessToken) | ||
| .tokenType(TokenType.ACCESS) | ||
| .expiresAt(accessExpiresAt) | ||
| .revoked(false) | ||
| .build(); | ||
|
|
||
| Token refreshTk = Token.builder() | ||
| .tokenId(refreshTokenId) | ||
| .user(user) | ||
| .tokenValue(refreshToken) | ||
| .tokenType(TokenType.REFRESH) | ||
| .expiresAt(refreshExpiresAt) | ||
| .revoked(false) | ||
| .build(); |
There was a problem hiding this comment.
약어는 사용하지 않는게 좋을 것 같아요! 물론 초반에 저희가 리뷰를 다 진행하다보니 TK = Token이라고 인지가 되지만, 이후에는 살짝 인지 부하가 발생할 것 같아서요!
| import lombok.Setter; | ||
|
|
||
| @Entity | ||
| @Getter |
There was a problem hiding this comment.
Setter는 선언하지 않는게 좋아보여요! 만일 값이 수정되어야한다면 목적이 들어나는 함수를 정의하도록 하는게 좋아보여요
| .compact(); | ||
| } | ||
|
|
||
| public String createRefreshToken(Long userId, String tokenId) { |
There was a problem hiding this comment.
createAccesssToken와 createRefreshToken가 거의 동알한데 통합할 수 없을까요?
| .revoked(false) | ||
| .build(); | ||
|
|
||
| tokenRepository.save(accesTk); |
There was a problem hiding this comment.
혹시 AccessToken을 저장하는 이유가 있을까요?
| Jwts.parser() | ||
| .verifyWith(secretKey) | ||
| .build() |
There was a problem hiding this comment.
매번 인스턴스를 생성하기보다는 PostContruct에서 한 번 만들어서 재활용할 수 있을 것 같아요
| public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> { | ||
| @Override | ||
| public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { | ||
| OAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultOAuth2UserService(); |
| @Lob | ||
| private String tokenValue; |
|
|
||
| @Getter | ||
| @Builder | ||
| public class LoginTokenResponse { |
📌 관련 이슈
🔍 작업 내용
OAuth2를 사용하여 소셜 로그인 기능 구현, 로그인 성공 후 accessToken, refreshToken 발급 아직 배치를 사용하진 않았음
📝 변경 사항
OAuth2UserService : 구글로부터 전달받은 사용자 정보를 서비스에 맞게 작성
OAuthAttributes : 구글로부터 응답데이터를 DTO로 변환
SuccessHandler : 로그인 성공시 AuthService를 호출하여 토큰 생성 -> 프론트엔드 지정 주소로 토큰을 담아 새로고침
💬 리뷰어에게