diff --git a/src/main/java/com/linku/backend/domain/user/User.java b/src/main/java/com/linku/backend/domain/user/User.java index f2b8b91..175f5cb 100644 --- a/src/main/java/com/linku/backend/domain/user/User.java +++ b/src/main/java/com/linku/backend/domain/user/User.java @@ -3,6 +3,7 @@ import com.linku.backend.domain.common.BaseEntity; import com.linku.backend.domain.oauth.dto.GoogleUserInfo; import com.linku.backend.global.auth.AuthRole; +import com.linku.backend.global.exception.LinkuException; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; @@ -12,6 +13,8 @@ import java.time.LocalDateTime; +import static com.linku.backend.global.response.ResponseCode.GOOGLE_MAIL_INVALID; + @Entity @Table(name = "users") @SuperBuilder @@ -35,6 +38,9 @@ public class User extends BaseEntity { @Column(nullable = false, unique = true, length = 30) private String providerId; + @Column(length = 1024) + private String picture; + @Column(length = 20) @Enumerated(EnumType.STRING) private AuthRole authRole; @@ -45,14 +51,16 @@ public static User guest(GoogleUserInfo userInfo) { return new User( userInfo.sub(), userInfo.email(), - userInfo.name() + userInfo.name(), + userInfo.picture() ); } - private User(String providerId, String gMail, String name) { + private User(String providerId, String gMail, String name, String picture) { this.providerId = providerId; this.gMail = gMail; this.name = name; + this.picture = picture; this.authRole = AuthRole.ROLE_GUEST; } @@ -60,4 +68,17 @@ public void updateInfo(String kuMail) { this.kuMail = kuMail; this.authRole = AuthRole.ROLE_MEMBER; } + + public String getGoogleId() { + if (gMail == null || gMail.isBlank()) { + return null; + } + + int atIndex = gMail.indexOf('@'); + if (atIndex <= 0) { + throw LinkuException.of(GOOGLE_MAIL_INVALID); + } + + return gMail.substring(0, atIndex); + } } \ No newline at end of file diff --git a/src/main/java/com/linku/backend/global/auth/controller/AuthController.java b/src/main/java/com/linku/backend/global/auth/controller/AuthController.java index 0dc1e97..a8dd16d 100644 --- a/src/main/java/com/linku/backend/global/auth/controller/AuthController.java +++ b/src/main/java/com/linku/backend/global/auth/controller/AuthController.java @@ -4,7 +4,9 @@ import com.linku.backend.domain.user.service.UserService; import com.linku.backend.global.auth.dto.KUMailRequest; import com.linku.backend.global.auth.dto.KUMailVerifyRequest; +import com.linku.backend.global.auth.dto.TokenReissueRequest; import com.linku.backend.global.auth.dto.UserInfoResponse; +import com.linku.backend.global.auth.service.AuthService; import com.linku.backend.global.auth.service.MailService; import com.linku.backend.global.jwt.JwtTokenService; import com.linku.backend.global.response.BaseResponse; @@ -22,6 +24,7 @@ public class AuthController { private final MailService mailService; private final UserService userService; + private final AuthService authService; @PostMapping("/send-code") public BaseResponse sendAuthCode(@Validated @RequestBody KUMailRequest request) { @@ -39,4 +42,10 @@ public BaseResponse verifyAuthCode(@Validated @RequestBody KUM UserInfoResponse response = userService.updateInfo(request.kuMail(), guestToken); return BaseResponse.of(ResponseCode.SUCCESS, response); } + + @PostMapping("/token") + public BaseResponse reissueToken(@RequestBody TokenReissueRequest request) { + UserInfoResponse response = authService.reissueToken(request.refreshToken()); + return BaseResponse.of(ResponseCode.SUCCESS, response); + } } diff --git a/src/main/java/com/linku/backend/global/auth/dto/TokenReissueRequest.java b/src/main/java/com/linku/backend/global/auth/dto/TokenReissueRequest.java new file mode 100644 index 0000000..5a95e5b --- /dev/null +++ b/src/main/java/com/linku/backend/global/auth/dto/TokenReissueRequest.java @@ -0,0 +1,4 @@ +package com.linku.backend.global.auth.dto; + +public record TokenReissueRequest(String refreshToken) { +} diff --git a/src/main/java/com/linku/backend/global/auth/dto/UserInfoResponse.java b/src/main/java/com/linku/backend/global/auth/dto/UserInfoResponse.java index cac4f92..8858aa5 100644 --- a/src/main/java/com/linku/backend/global/auth/dto/UserInfoResponse.java +++ b/src/main/java/com/linku/backend/global/auth/dto/UserInfoResponse.java @@ -5,7 +5,8 @@ public record UserInfoResponse( String accessToken, String refreshToken, - Long userId, + String googleId, + String profileImage, String name, String kuMail ) { @@ -13,7 +14,8 @@ public static UserInfoResponse from(User user, AuthTokenResponse authTokenRespon return new UserInfoResponse( authTokenResponse.accessToken(), authTokenResponse.refreshToken(), - user.getUserId(), + user.getGoogleId(), // 구글 이메일이 등록되어 있지 않으면 null이 반환됨 + user.getPicture(), user.getName(), user.getKuMail() ); diff --git a/src/main/java/com/linku/backend/global/auth/service/AuthService.java b/src/main/java/com/linku/backend/global/auth/service/AuthService.java new file mode 100644 index 0000000..f50d6dd --- /dev/null +++ b/src/main/java/com/linku/backend/global/auth/service/AuthService.java @@ -0,0 +1,30 @@ +package com.linku.backend.global.auth.service; + +import com.linku.backend.domain.user.User; +import com.linku.backend.domain.user.service.UserService; +import com.linku.backend.global.auth.AuthUser; +import com.linku.backend.global.auth.dto.AuthTokenResponse; +import com.linku.backend.global.auth.dto.UserInfoResponse; +import com.linku.backend.global.jwt.JwtTokenService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class AuthService { + + private final JwtTokenService jwtTokenService; + private final UserService userService; + + @Transactional + public UserInfoResponse reissueToken(String refreshToken) { + AuthUser authUser = (AuthUser) jwtTokenService.validateToken(refreshToken, JwtTokenService.REFRESH); + User user = userService.getUserById(authUser.getId()); + AuthTokenResponse authToken = jwtTokenService.generateAuthToken(user); + return UserInfoResponse.from(user, authToken); + } +} \ No newline at end of file diff --git a/src/main/java/com/linku/backend/global/jwt/JwtTokenService.java b/src/main/java/com/linku/backend/global/jwt/JwtTokenService.java index 94f3ee7..fa25715 100644 --- a/src/main/java/com/linku/backend/global/jwt/JwtTokenService.java +++ b/src/main/java/com/linku/backend/global/jwt/JwtTokenService.java @@ -72,7 +72,11 @@ public String generateGuestToken(Long userId) { private String generateToken(Claims claims, long expiration, String type) { claims.put("type", type); - return Jwts.builder().setClaims(claims).setIssuedAt(new Date(System.currentTimeMillis())).setExpiration(new Date(System.currentTimeMillis() + expiration)).signWith(SignatureAlgorithm.HS256, secretKey).compact(); + return Jwts.builder().setClaims(claims) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + expiration)) + .signWith(SignatureAlgorithm.HS256, secretKey) + .compact(); } // 토큰 검증 이후에 사용 diff --git a/src/main/java/com/linku/backend/global/response/ResponseCode.java b/src/main/java/com/linku/backend/global/response/ResponseCode.java index 7e89a34..a9be40c 100644 --- a/src/main/java/com/linku/backend/global/response/ResponseCode.java +++ b/src/main/java/com/linku/backend/global/response/ResponseCode.java @@ -56,7 +56,8 @@ public enum ResponseCode { KUMAIL_ALREADY(false, 5014, "이미 존재하는 건국대학교 이메일입니다."), MAIL_SEND_FAIL(false, 5015, "메일 전송 중 오류가 발생했습니다."), AUTH_CODE_INVALID(false, 5016, "이메일 인증에 실패했습니다. 인증 코드가 올바르지 않습니다."), - + GOOGLE_MAIL_INVALID(false, 5017, "구글 이메일 형식이 올바르지 않습니다."), + // 6000대 : Crawling 관련 요청 성공/실패 CRAWLING_FAILED(false, 6000, "크롤링을 실패하였습니다."), CRAWLING_PARSING_FAILED(false, 6001, "크롤링 파싱을 실패하였습니다."),