diff --git a/src/main/java/com/teamEWSN/gitdeun/common/config/SchedulingConfig.java b/src/main/java/com/teamEWSN/gitdeun/common/config/SchedulingConfig.java new file mode 100644 index 0000000..9590aee --- /dev/null +++ b/src/main/java/com/teamEWSN/gitdeun/common/config/SchedulingConfig.java @@ -0,0 +1,9 @@ +package com.teamEWSN.gitdeun.common.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class SchedulingConfig { +} diff --git a/src/main/java/com/teamEWSN/gitdeun/common/config/SecurityPath.java b/src/main/java/com/teamEWSN/gitdeun/common/config/SecurityPath.java index aa72761..9581677 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/config/SecurityPath.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/config/SecurityPath.java @@ -5,18 +5,19 @@ public class SecurityPath { // permitAll public static final String[] PUBLIC_ENDPOINTS = { - "/api/signup", - "/api/login", "/api/token/refresh", - "/api/users/check-duplicate", - "/" + "/api/auth/oauth/refresh/*", + "/", + }; // hasRole("USER") public static final String[] USER_ENDPOINTS = { + "/api/auth/connect/github/state", "/api/users/me", "/api/users/me/**", - "/api/logout" + "/api/logout", + "/api/repos/**" }; // hasRole("ADMIN") diff --git a/src/main/java/com/teamEWSN/gitdeun/common/fastapi/dto/AnalysisResultDto.java b/src/main/java/com/teamEWSN/gitdeun/common/fastapi/dto/AnalysisResultDto.java index ff5d85f..bb0553c 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/fastapi/dto/AnalysisResultDto.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/fastapi/dto/AnalysisResultDto.java @@ -9,7 +9,6 @@ public class AnalysisResultDto { // FastAPI가 반환하는 Repo 관련 정보 private String defaultBranch; - private String language; private String description; private LocalDateTime githubLastUpdatedAt; diff --git a/src/main/java/com/teamEWSN/gitdeun/common/jwt/JwtToken.java b/src/main/java/com/teamEWSN/gitdeun/common/jwt/JwtToken.java index 66a7849..0ca4da4 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/jwt/JwtToken.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/jwt/JwtToken.java @@ -11,4 +11,13 @@ public class JwtToken { private String grantType; private String accessToken; private String refreshToken; + + // 정적 메서드 + public static JwtToken of(String accessToken, String refreshToken) { + return JwtToken.builder() + .grantType("Bearer") + .accessToken(accessToken) + .refreshToken(refreshToken) + .build(); + } } diff --git a/src/main/java/com/teamEWSN/gitdeun/common/jwt/JwtTokenProvider.java b/src/main/java/com/teamEWSN/gitdeun/common/jwt/JwtTokenProvider.java index 83e2de5..281e51b 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/jwt/JwtTokenProvider.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/jwt/JwtTokenProvider.java @@ -1,8 +1,8 @@ package com.teamEWSN.gitdeun.common.jwt; -import com.teamEWSN.gitdeun.common.exception.GlobalException; -import com.teamEWSN.gitdeun.common.exception.ErrorCode; import com.teamEWSN.gitdeun.user.entity.Role; +import com.teamEWSN.gitdeun.user.entity.User; +import com.teamEWSN.gitdeun.user.service.UserService; import io.jsonwebtoken.*; import io.jsonwebtoken.security.Keys; import lombok.Getter; @@ -11,11 +11,11 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.core.oidc.user.OidcUser; +import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Component; import javax.crypto.SecretKey; -import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.UUID; @@ -27,6 +27,9 @@ public class JwtTokenProvider { private final SecretKey secretKey; + @Autowired + private UserService userService; + @Autowired private RefreshTokenService refreshTokenService; @@ -48,76 +51,139 @@ public JwtTokenProvider(@Value("${jwt.secret-key}") String secretKey) { this.secretKey = Keys.hmacShaKeyFor(keyBytes); } - // 토큰 생성 - 유저 정보 이용 public JwtToken generateToken(Authentication authentication) { + Object principal = authentication.getPrincipal(); + + Long userId; + Role role; + + switch (principal) { + case CustomUserPrincipal p -> { + userId = p.getId(); + role = Role.valueOf(p.getRole()); + } + case OidcUser oidc -> { + userId = userService.upsertAndGetId( + oidc.getEmail(), oidc.getFullName(), oidc.getPicture(), oidc.getFullName()); + role = Role.USER; + } + case OAuth2User oauth2 -> { + String email = (String) oauth2.getAttributes().get("email"); + userId = userService.upsertAndGetId( + email, (String) oauth2.getAttributes().get("name"), + (String) oauth2.getAttributes().get("avatar_url"), (String) oauth2.getAttributes().get("login")); + role = Role.USER; + } + case null, default -> throw new IllegalStateException("Unsupported principal"); + } - long now = (new Date()).getTime(); - Date accessTokenExpiration = new Date(now + accessTokenExpired * 1000); - - CustomUserPrincipal userPrincipal = (CustomUserPrincipal) authentication.getPrincipal(); - - Long userId = ((CustomUserDetails) userPrincipal).getId(); + long now = System.currentTimeMillis(); + Date exp = new Date(now + accessTokenExpired * 1000); String jti = UUID.randomUUID().toString(); - // Access Token 생성 + String accessToken = Jwts.builder() - .subject(String.valueOf(userId)) // Subject를 불변값인 userId로 설정 - .issuedAt(new Date()) // 발행 시간 - .id(jti) // blacklist 관리를 위한 jwt token id - .claim("email", userPrincipal.getEmail()) // 이메일 - .claim("nickname", userPrincipal.getNickname()) // 닉네임 - .claim("role", userPrincipal.getRole()) // 사용자 역할(Role) - .claim("name",userPrincipal.getName()) - .claim("profileImage", userPrincipal.getProfileImage()) // 프로필 이미지 추가 - .expiration(accessTokenExpiration) // 만료 시간 - .signWith(secretKey) // 서명 + .subject(String.valueOf(userId)) + .issuedAt(new Date(now)) + .id(jti) + .claim("role", role.name()) + .expiration(exp) + .signWith(secretKey) .compact(); - // Refresh Token 생성 (임의의 값 생성) String refreshToken = UUID.randomUUID().toString(); + refreshTokenService.saveRefreshToken(refreshToken, userId, refreshTokenExpired); - // Redis에 Refresh Token 정보 저장 - refreshTokenService.saveRefreshToken( refreshToken, userPrincipal.getEmail(), refreshTokenExpired); - - - // JWT Token 객체 반환 - return JwtToken.builder() - .grantType("Bearer") - .accessToken(accessToken) - .refreshToken(refreshToken) - .build(); - + return JwtToken.of(accessToken, refreshToken); } + // DB 조회 후 UserDetails 생성 + public Authentication getAuthentication(String token) { + Claims claims = jwtTokenParser.parseClaims(token); + Long userId = Long.valueOf(claims.getSubject()); + Role role = Role.valueOf(claims.get("role", String.class)); - // 토큰에서 유저 정보 추출 - public Authentication getAuthentication(String accessToken) { - // 토큰에서 Claims 추출 - Claims claims = jwtTokenParser.parseClaims(accessToken); - - // 권한 정보 확인 - if (claims.get("role") == null) { - throw new GlobalException(ErrorCode.ROLE_NOT_FOUND); - } - - // 클레임에서 모든 사용자 정보 추출 - Long id = Long.parseLong(claims.getSubject()); - String email = claims.get("email", String.class); - String nickname = claims.get("nickname", String.class); - String name = claims.get("name", String.class); - String profileImage = claims.get("profileImage", String.class); - Role role = Role.valueOf(claims.get("role", String.class)); + User user = userService.findById(userId); - CustomUserDetails userDetails = new CustomUserDetails(id, email, nickname, profileImage, role, name); - - Collection authorities = - Collections.singletonList(role::name); - - // Authentication 객체 반환 - return new UsernamePasswordAuthenticationToken(userDetails, null, authorities); + CustomUserDetails userDetails = + new CustomUserDetails(user.getId(), user.getEmail(), + user.getNickname(), user.getProfileImage(), + role, user.getName()); + return new UsernamePasswordAuthenticationToken( + userDetails, null, Collections.singletonList(role::name)); } +// // 토큰 생성 - 유저 정보 이용 +// public JwtToken generateToken(Authentication authentication) { +// +// long now = (new Date()).getTime(); +// Date accessTokenExpiration = new Date(now + accessTokenExpired * 1000); +// +// CustomUserPrincipal userPrincipal = (CustomUserPrincipal) authentication.getPrincipal(); +// +// Long userId = ((CustomUserDetails) userPrincipal).getId(); +// +// String jti = UUID.randomUUID().toString(); +// // Access Token 생성 +// String accessToken = Jwts.builder() +// .subject(String.valueOf(userId)) // Subject를 불변값인 userId로 설정 +// .issuedAt(new Date()) // 발행 시간 +// .id(jti) // blacklist 관리를 위한 jwt token id +// .claim("email", userPrincipal.getEmail()) // 이메일 +// .claim("nickname", userPrincipal.getNickname()) // 닉네임 +// .claim("role", userPrincipal.getRole()) // 사용자 역할(Role) +// .claim("name",userPrincipal.getName()) +// .claim("profileImage", userPrincipal.getProfileImage()) // 프로필 이미지 추가 +// .expiration(accessTokenExpiration) // 만료 시간 +// .signWith(secretKey) // 서명 +// .compact(); +// +// // Refresh Token 생성 (임의의 값 생성) +// String refreshToken = UUID.randomUUID().toString(); +// +// // Redis에 Refresh Token 정보 저장 +// refreshTokenService.saveRefreshToken( refreshToken, userPrincipal.getEmail(), refreshTokenExpired); +// +// +// // JWT Token 객체 반환 +// return JwtToken.builder() +// .grantType("Bearer") +// .accessToken(accessToken) +// .refreshToken(refreshToken) +// .build(); +// +// } +// +// +// // 토큰에서 유저 정보 추출 +// public Authentication getAuthentication(String accessToken) { +// // 토큰에서 Claims 추출 +// Claims claims = jwtTokenParser.parseClaims(accessToken); +// +// // 권한 정보 확인 +// if (claims.get("role") == null) { +// throw new GlobalException(ErrorCode.ROLE_NOT_FOUND); +// } +// +// // 클레임에서 모든 사용자 정보 추출 +// Long id = Long.parseLong(claims.getSubject()); +// String email = claims.get("email", String.class); +// String nickname = claims.get("nickname", String.class); +// String name = claims.get("name", String.class); +// String profileImage = claims.get("profileImage", String.class); +// Role role = Role.valueOf(claims.get("role", String.class)); +// +// CustomUserDetails userDetails = new CustomUserDetails(id, email, nickname, profileImage, role, name); +// +// Collection authorities = +// Collections.singletonList(role::name); +// +// // Authentication 객체 반환 +// return new UsernamePasswordAuthenticationToken(userDetails, null, authorities); +// +// } + // 토큰 정보 검증 public boolean validateToken(String token) { log.debug("validateToken start"); diff --git a/src/main/java/com/teamEWSN/gitdeun/common/jwt/RefreshToken.java b/src/main/java/com/teamEWSN/gitdeun/common/jwt/RefreshToken.java index a2ca41f..e43edea 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/jwt/RefreshToken.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/jwt/RefreshToken.java @@ -7,6 +7,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.redis.core.RedisHash; import org.springframework.data.redis.core.TimeToLive; +import org.springframework.data.redis.core.index.Indexed; @Getter @AllArgsConstructor @@ -18,7 +19,8 @@ public class RefreshToken { @Id private String refreshToken; - private String email; + @Indexed + private Long userId; private Long issuedAt; // Time to live (TTL) 설정, Redis에 만료 시간을 설정 diff --git a/src/main/java/com/teamEWSN/gitdeun/common/jwt/RefreshTokenService.java b/src/main/java/com/teamEWSN/gitdeun/common/jwt/RefreshTokenService.java index 51e4818..f8b020f 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/jwt/RefreshTokenService.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/jwt/RefreshTokenService.java @@ -13,10 +13,10 @@ public class RefreshTokenService { private final RefreshTokenRepository refreshTokenRepository; - public void saveRefreshToken(String refreshToken, String email, long refreshTokenExpired) { + public void saveRefreshToken(String refreshToken, Long userId, long refreshTokenExpired) { RefreshToken token = RefreshToken.builder() .refreshToken(refreshToken) - .email(email) + .userId(userId) .issuedAt(System.currentTimeMillis()) .ttl(refreshTokenExpired) // @TimeToLive에 사용될 만료 시간 .build(); diff --git a/src/main/java/com/teamEWSN/gitdeun/common/oauth/handler/CustomOAuth2SuccessHandler.java b/src/main/java/com/teamEWSN/gitdeun/common/oauth/handler/CustomOAuth2SuccessHandler.java index d96969f..912d06b 100644 --- a/src/main/java/com/teamEWSN/gitdeun/common/oauth/handler/CustomOAuth2SuccessHandler.java +++ b/src/main/java/com/teamEWSN/gitdeun/common/oauth/handler/CustomOAuth2SuccessHandler.java @@ -11,10 +11,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponentsBuilder; import java.io.IOException; @@ -32,23 +32,51 @@ public class CustomOAuth2SuccessHandler extends SimpleUrlAuthenticationSuccessHa private String frontUrl; @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { - OAuth2AuthenticationToken authToken = (OAuth2AuthenticationToken) authentication; - OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal(); - String state = request.getParameter("state"); + public void onAuthenticationSuccess(HttpServletRequest req, + HttpServletResponse res, + Authentication auth) throws IOException { - String purpose = oAuthStateService.consumeState(state); // "connect:42" 또는 null + String state = req.getParameter("state"); + String purpose = state != null ? oAuthStateService.consumeState(state) : null; + + // 1) 계정 연동 시나리오 if (purpose != null && purpose.startsWith("connect:")) { - Long userId = Long.parseLong(purpose.split(":")[1]); - authService.connectGithubAccount(oAuth2User, userId); - response.sendRedirect(frontUrl + "/oauth/callback#connected=true"); + handleAccountConnection(purpose, (OAuth2User) auth.getPrincipal(), res); return; } - // 일반 로그인 흐름 + // 2) 일반 로그인 + handleStandardLogin(req, res, auth); + } + + /** + * 일반 로그인 성공 시 JWT 토큰을 발급 및 클라이언트로 리디렉션 + */ + private void handleStandardLogin(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { + // JWT 액세스 토큰과 리프레시 토큰을 생성합니다. JwtToken jwtToken = jwtTokenProvider.generateToken(authentication); + + // 리프레시 토큰은 보안을 위해 HttpOnly 쿠키에 저장합니다. cookieUtil.setCookie(response, "refreshToken", jwtToken.getRefreshToken(), jwtTokenProvider.getRefreshTokenExpired()); - String targetUrl = frontUrl + "/oauth/callback#accessToken=" + jwtToken.getAccessToken(); + + // 액세스 토큰은 URL 프래그먼트로 프론트엔드에 전달합니다. + String targetUrl = UriComponentsBuilder.fromUriString(frontUrl + "/oauth/callback") + .fragment("accessToken=" + jwtToken.getAccessToken()) + .build() + .toUriString(); + + clearAuthenticationAttributes(request); // 세션 클린업 getRedirectStrategy().sendRedirect(request, response, targetUrl); } + + /** + * 기존 계정에 새로운 소셜 계정을 연동하는 흐름을 처리 + */ + private void handleAccountConnection(String purpose, OAuth2User oAuth2User, HttpServletResponse response) throws IOException { + Long userId = Long.parseLong(purpose.split(":")[1]); + authService.connectGithubAccount(oAuth2User, userId); // 계정 연동 로직 호출 + + String targetUrl = frontUrl + "/oauth/callback#connected=true"; + response.sendRedirect(targetUrl); + } } diff --git a/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoResponseDto.java b/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoResponseDto.java index 870c276..d2eddd1 100644 --- a/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoResponseDto.java +++ b/src/main/java/com/teamEWSN/gitdeun/repo/dto/RepoResponseDto.java @@ -12,7 +12,6 @@ public class RepoResponseDto { private final Long repoId; private final String githubRepoUrl; private final String defaultBranch; - private final String language; private final String description; private final LocalDateTime githubLastUpdatedAt; diff --git a/src/main/java/com/teamEWSN/gitdeun/repo/entity/Repo.java b/src/main/java/com/teamEWSN/gitdeun/repo/entity/Repo.java index 8f0be06..83f4000 100644 --- a/src/main/java/com/teamEWSN/gitdeun/repo/entity/Repo.java +++ b/src/main/java/com/teamEWSN/gitdeun/repo/entity/Repo.java @@ -24,9 +24,6 @@ public class Repo { @Column(name = "default_branch", length = 100) private String defaultBranch; // 기본 브랜치 - @Column(length = 50) - private String language; // 주요 언어 - @Column(columnDefinition = "TEXT") private String description; // 설명 @@ -35,16 +32,14 @@ public class Repo { @Builder - public Repo(String githubRepoUrl, String defaultBranch, String language, String description, LocalDateTime githubLastUpdatedAt) { + public Repo(String githubRepoUrl, String defaultBranch, String description, LocalDateTime githubLastUpdatedAt) { this.githubRepoUrl = githubRepoUrl; this.defaultBranch = defaultBranch; - this.language = language; this.description = description; this.githubLastUpdatedAt = githubLastUpdatedAt; } public void updateWithAnalysis(AnalysisResultDto result) { - this.language = result.getLanguage(); this.description = result.getDescription(); this.githubLastUpdatedAt = result.getGithubLastUpdatedAt(); } diff --git a/src/main/java/com/teamEWSN/gitdeun/user/controller/AuthController.java b/src/main/java/com/teamEWSN/gitdeun/user/controller/AuthController.java index 2f8954a..4ad229b 100644 --- a/src/main/java/com/teamEWSN/gitdeun/user/controller/AuthController.java +++ b/src/main/java/com/teamEWSN/gitdeun/user/controller/AuthController.java @@ -59,7 +59,7 @@ public ResponseEntity logout( } // 토큰 재발급 - @PostMapping("/token/refresh") + @GetMapping("/token/refresh") public ResponseEntity refreshAccessToken( @CookieValue(name = "refreshToken") String refreshToken, HttpServletResponse response) { diff --git a/src/main/java/com/teamEWSN/gitdeun/user/controller/UserSettingController.java b/src/main/java/com/teamEWSN/gitdeun/user/controller/UserSettingController.java index 8c26416..e865b54 100644 --- a/src/main/java/com/teamEWSN/gitdeun/user/controller/UserSettingController.java +++ b/src/main/java/com/teamEWSN/gitdeun/user/controller/UserSettingController.java @@ -19,7 +19,7 @@ public class UserSettingController { private final UserSettingService userSettingService; /** - * 현재 로그인된 사용자의 설정을 조회합니다. + * 현재 로그인된 사용자의 설정을 조회 * @param userDetails 인증된 사용자 정보 * @return 현재 설정 정보를 담은 응답 */ @@ -32,12 +32,12 @@ public ResponseEntity getUserSettings( } /** - * 현재 로그인된 사용자의 설정을 변경합니다. + * 현재 로그인된 사용자의 설정을 변경 * @param userDetails 인증된 사용자 정보 * @param requestDto 변경할 설정 정보를 담은 요청 DTO * @return 변경된 설정 정보를 담은 응답 */ - @PatchMapping // 리소스의 일부만 변경하므로 PATCH가 더 적합합니다. + @PatchMapping public ResponseEntity updateUserSettings( @AuthenticationPrincipal CustomUserDetails userDetails, @Valid @RequestBody UserSettingUpdateRequestDto requestDto diff --git a/src/main/java/com/teamEWSN/gitdeun/user/entity/Role.java b/src/main/java/com/teamEWSN/gitdeun/user/entity/Role.java index be3d139..bee52db 100644 --- a/src/main/java/com/teamEWSN/gitdeun/user/entity/Role.java +++ b/src/main/java/com/teamEWSN/gitdeun/user/entity/Role.java @@ -4,7 +4,7 @@ public enum Role implements GrantedAuthority { ROLE_USER, - ROLE_ADMIN; + ROLE_ADMIN, USER; @Override public String getAuthority() { diff --git a/src/main/java/com/teamEWSN/gitdeun/user/entity/User.java b/src/main/java/com/teamEWSN/gitdeun/user/entity/User.java index 0d0c532..7cb2495 100644 --- a/src/main/java/com/teamEWSN/gitdeun/user/entity/User.java +++ b/src/main/java/com/teamEWSN/gitdeun/user/entity/User.java @@ -50,6 +50,12 @@ public User(String name, String nickname, String email, String profileImage, Rol this.role = role; } + public User updateProfile(String name, String profileImage) { + this.name = name; + this.profileImage = profileImage; + return this; // 메소드 체이닝을 위해 this 반환 + } + // 회원 탈퇴 처리 public void markAsDeleted() { this.deletedAt = LocalDateTime.now(); diff --git a/src/main/java/com/teamEWSN/gitdeun/user/service/AuthService.java b/src/main/java/com/teamEWSN/gitdeun/user/service/AuthService.java index 4543ca7..b9d30ab 100644 --- a/src/main/java/com/teamEWSN/gitdeun/user/service/AuthService.java +++ b/src/main/java/com/teamEWSN/gitdeun/user/service/AuthService.java @@ -65,10 +65,10 @@ public JwtToken refreshTokens(String refreshToken) { .orElseThrow(() -> new GlobalException(ErrorCode.INVALID_REFRESH_TOKEN)); // 토큰에서 email 정보 추출 - String email = tokenDetails.getEmail(); + Long userId = tokenDetails.getUserId(); - // email로 사용자 정보 조회 - User user = userService.findUserByEmail(email); + // userId로 사용자 정보 조회 + User user = userService.findById(userId); Authentication authentication = createAuthentication(user); // 기존 리프레시 토큰은 DB에서 제거 (순환) diff --git a/src/main/java/com/teamEWSN/gitdeun/user/service/UserService.java b/src/main/java/com/teamEWSN/gitdeun/user/service/UserService.java index 9e2cd66..133620d 100644 --- a/src/main/java/com/teamEWSN/gitdeun/user/service/UserService.java +++ b/src/main/java/com/teamEWSN/gitdeun/user/service/UserService.java @@ -8,6 +8,7 @@ import com.teamEWSN.gitdeun.common.oauth.service.GoogleApiHelper; import com.teamEWSN.gitdeun.common.oauth.entity.SocialConnection; import com.teamEWSN.gitdeun.user.dto.UserResponseDto; +import com.teamEWSN.gitdeun.user.entity.Role; import com.teamEWSN.gitdeun.user.entity.User; import com.teamEWSN.gitdeun.user.mapper.UserMapper; import com.teamEWSN.gitdeun.user.repository.UserRepository; @@ -87,4 +88,25 @@ public User findUserByEmail(String email) { .orElseThrow(() -> new GlobalException(ErrorCode.USER_NOT_FOUND_BY_EMAIL)); } + + // 아이디로 회원 검색 + @Transactional(readOnly = true) + public User findById(Long id) { + return userRepository.findByIdAndDeletedAtIsNull(id) + .orElseThrow(() -> new GlobalException(ErrorCode.USER_NOT_FOUND_BY_ID)); + + } + + @Transactional + public Long upsertAndGetId(String email, String name, String picture, String nickname) { + return userRepository.findByEmailAndDeletedAtIsNull(email) + .map(u -> u.updateProfile(name, picture)) // 이미 있으면 갱신 + .orElseGet(() -> userRepository.save( + User.builder() + .email(email).name(name).profileImage(picture) + .nickname(nickname) + .role(Role.USER) + .build())) + .getId(); + } } \ No newline at end of file diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 8fa6f61..f8f3507 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -9,7 +9,7 @@ spring: client: registration: google: - redirect-uri: http://localhost:8080/login/oauth2/code/google # /oauth2/authorization/google 로그인 시작 URL + redirect-uri: http://localhost:8080/login/oauth2/code/google github: client-id: ${GITHUB_DEV_CLIENT_ID} client-secret: ${GITHUB_DEV_CLIENT_SECRET} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index c7fd4e8..fff3e2f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -19,7 +19,6 @@ spring: ddl-auto: create # create # update properties: hibernate: - dialect: org.hibernate.dialect.MySQL8Dialect format_sql: true # SQL 로그를 보기 좋게 포맷 auto_quote_keyword: true # 예약어를 자동으로 따옴표 처리 order_inserts: true @@ -33,7 +32,7 @@ spring: google: client-id: ${GOOGLE_CLIENT_ID} client-secret: ${GOOGLE_CLIENT_SECRET} - scope: profile, email + scope: openid, email, profile github: scope: user:email, repo profiles: