Skip to content

Commit

Permalink
Merge pull request #11 from COM-MA/feature/#9
Browse files Browse the repository at this point in the history
[feat] 구글 로그인 구현
  • Loading branch information
hysong4u authored Feb 20, 2024
2 parents adfb8ac + 10e57ca commit f47a5c2
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.example.comma.domain.user.controller;


import com.example.comma.domain.user.dto.response.LoginResponseDto;
import com.example.comma.domain.user.dto.response.UserInfoResponseDto;
import com.example.comma.domain.user.service.OauthService;
import com.example.comma.domain.user.service.UserService;
import com.example.comma.global.common.SuccessResponse;

import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RequiredArgsConstructor
@RestController
@RequestMapping(value = "/login/oauth2", produces = "application/json")
public class OauthController {

private final OauthService oauthService;
private final UserService userService;

@GetMapping("/code/{registrationId}")
ResponseEntity<SuccessResponse<?>> googleLogin(@RequestParam (name = "code") String code, @PathVariable (name = "registrationId") String registrationId) {

Long userId = oauthService.socialLogin(code, registrationId);
String accessToken = userService.issueNewAccessToken(userId);
String randomNickname = userService.generateNickname();

LoginResponseDto response = new LoginResponseDto(accessToken, randomNickname);

return SuccessResponse.ok(response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,6 @@ public ResponseEntity<SuccessResponse<?>> getHome(@UserId Long userId) {
return SuccessResponse.ok(responseData);
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.comma.domain.user.dto.response;

public record LoginResponseDto(
String accessToken,
String RandomNickname
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.comma.domain.user.dto.response;

public record UserInfoResponseDto(
Long id,
String socialId,
String name,
String email,
String profileImage
) {
}
17 changes: 16 additions & 1 deletion src/main/java/com/example/comma/domain/user/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.example.comma.global.common.BaseTimeEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

Expand All @@ -23,15 +24,29 @@ public class User extends BaseTimeEntity {

private String nickname;

private String name;

private String email;

private String profileImage;

@Column(nullable = false)
private Long socialId;
private String socialId;

@OneToMany(mappedBy = "user")
private List<UserFairytale> userFairytaleList;

@OneToMany(mappedBy = "user")
private List<UserCard> userCardList;

@Builder
public User(String socialId, String name, String email, String profileImage) {
this.socialId = socialId;
this.name = name;
this.email = email;
this.profileImage = profileImage;
}

public void setNickname(String nickname) {
this.nickname = nickname;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@

public interface UserRepository extends JpaRepository<User, Long> {

User findBySocialId(String socialId);
}
104 changes: 104 additions & 0 deletions src/main/java/com/example/comma/domain/user/service/OauthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.example.comma.domain.user.service;
import com.example.comma.domain.user.dto.response.UserInfoResponseDto;
import com.example.comma.domain.user.dto.response.UserTokenResponseDto;
import com.example.comma.domain.user.entity.User;
import com.example.comma.domain.user.repository.UserRepository;
import com.example.comma.global.config.auth.jwt.JwtProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;

@Service
@Transactional
@RequiredArgsConstructor
public class OauthService {

private final Environment env;
private final UserRepository userRepository;
private final JwtProvider jwtProvider;

private final RestTemplate restTemplate = new RestTemplate();

@Value("${spring.security.oauth2.client.registration.google.client-id}")
private String clientId;

@Value("${spring.security.oauth2.client.registration.google.client-secret}")
private String clientSecret;

@Value("${spring.security.oauth2.client.registration.google.redirect-uri}")
private String redirectUri;

public Long socialLogin(String code, String registrationId) {
String accessToken = getOauthToken(code, registrationId);
JsonNode userResourceNode = getUserResource(accessToken, registrationId);
String socialId = userResourceNode.get("id").asText();
String email = userResourceNode.get("email").asText();
String nickname = userResourceNode.get("name").asText();
String profileImage = userResourceNode.get("picture").asText();
UserInfoResponseDto user = saveMember(socialId, nickname, email, profileImage);
Long userId = user.id();
return userId;

}

public String getOauthToken(String authorizationCode, String registrationId) {
String tokenUri = env.getProperty("oauth2." + registrationId + ".token-uri");

MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("code", authorizationCode);
params.add("client_id", clientId);
params.add("client_secret", clientSecret);
params.add("redirect_uri", redirectUri);
params.add("grant_type", "authorization_code");

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

HttpEntity entity = new HttpEntity(params, headers);

ResponseEntity<JsonNode> responseNode = restTemplate.exchange(tokenUri, HttpMethod.POST, entity, JsonNode.class);
JsonNode accessTokenNode = responseNode.getBody();
String accessToken = accessTokenNode.get("access_token").asText();
return accessToken;
}

private JsonNode getUserResource(String accessToken, String registrationId) {
String resourceUri = env.getProperty("oauth2."+registrationId+".resource-uri");

HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + accessToken);
HttpEntity entity = new HttpEntity(headers);
return restTemplate.exchange(resourceUri, HttpMethod.GET, entity, JsonNode.class).getBody();
}

public UserInfoResponseDto saveMember(String socialId, String name, String email, String profileImage) {
User existMember = userRepository.findBySocialId(socialId);

if (existMember == null) {
User user = User.builder()
.socialId(socialId)
.name(name)
.email(email)
.profileImage(profileImage)
.build();
userRepository.save(user);

return new UserInfoResponseDto(user.getId(), user.getSocialId(), user.getName(), user.getEmail(), user.getProfileImage());
}

return new UserInfoResponseDto(existMember.getId(), existMember.getSocialId(), existMember.getName(), existMember.getEmail(), existMember.getProfileImage());
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Random;

@RequiredArgsConstructor
@Service
Expand All @@ -33,7 +34,7 @@ public UserTokenResponseDto getToken(Long memberId) {
return new UserTokenResponseDto(accessToken, refreshToken);
}

private String issueNewAccessToken(Long memberId) {
public String issueNewAccessToken(Long memberId) {
return jwtProvider.getIssueToken(memberId, true);
}

Expand Down Expand Up @@ -74,5 +75,28 @@ public HomepageResponseDto getHome(Long userId) {
);
}

private static final String[] ADJECTIVES = {"행복한", "밝은", "용감한", "영리한", "친절한",
"신나는", "귀여운", "날렵한", "총명한", "명랑한",
"따뜻한", "자유로운", "열정적인", "창의적인", "성실한",
"유쾌한", "현명한", "도전적인", "낙천적인", "포근한"};

private static final String[] NOUNS = {"용", "별", "탐험가", "불사조", "여행",
"모험자", "해변", "드래곤", "비행기", "오후",
"해적", "마법사", "코끼리", "책", "음악",
"강", "손", "꽃", "천사", "바다"};
public static String generateNickname() {
String adjective = getRandomElement(ADJECTIVES);
String noun = getRandomElement(NOUNS);
return adjective +" "+ noun ;
}

private static String getRandomElement(String[] array) {
Random random = new Random();
int randomIndex = random.nextInt(array.length);
return array[randomIndex];
}




}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class SecurityConfig {

private static final String[] whiteList = {"/",
"api/user/token/**",
"login/oauth2/code/google/**",
};

@Bean
Expand Down

0 comments on commit f47a5c2

Please sign in to comment.