Oauth2.0
사용자가 애플리케이션 또는 웹 사이트에 로그인할 때 사용되는 프로토콜 중 하나. 이 프로토콜은 보안된 방식으로 사용자의 정보를 제공하고, 다른 웹 사이트나 애플리케이션에서 해당 정보를 사용할 수 있도록 한다.
- 자주 사용하지 않는 웹사이트에 개인정보를 입력해서 회원가입을 해야 하나? 할 때 간단하게 소셜 로그인을 사용해서 이용할 수 있다.
구글소셜로그인을 위한 준비가 안되었다면 아래 링크를 통해 설정한 뒤 본 게시글을 따라 해야 한다.
구글 소셜로그인을 위한 설정(Spring + Oauth2.0)
1. 구글 API 콘솔 들어가기 https://console.cloud.google.com/projectselector2/apis/credentials/consent?authuser=2&supportedpurview=project Google 클라우드 플랫폼 로그인 Google 클라우드 플랫폼으로 이동 accounts.google.com 위 링
ngwdeveloper.tistory.com
1. Dto 설정
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class OauthUserDto {
private String id;
private String nickname;
private String email;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class OauthTokenDto {
private String accessToken;
}
OauthTokenDto - 액세스 토큰을 저장할 Dto
OauthUserDto - 엑세스 토큰을 이용해서 사용자의 정보를 저장할 Dto
2. 엔티티 설정
public User(OauthUserDto userDto, String password, UserRoleEnum role){
this.username = userDto.getEmail();
this.password = password;
this.nickname = userDto.getNickname();
this.introduction = "-";
this.role = role;
}
public User googleIdUpdate(String googleId){
this.googleId = googleId;
return this;
}
이부분은 본인의 User객체의 저장하는 목록에 따라 다를 수 있다.
나는 유저이름, 닉네임을 토큰을 이용해서 가져왔다. 또한 password, introduction, role만 설정해 주었다.
googleIdUpdate 메서드는 내가 설정해 둔 칼럼에 값을 추가할 수 있도록 만들어뒀다.
3. 레포지토리 설정
Optional<User> findByGoogleId(String googleId);
중복가입을 체크하기 위해 UserRepository에 googleId로 유저를 검색할 수 있도록 Optional형식으로 코드를 추가해 줬다.
4. 통합 서비스 설정(카카오, 네이버, 구글)
public interface OauthService {
OauthTokenDto socialLogin(String code) throws JsonProcessingException, UnsupportedEncodingException;
String getToken(String code) throws JsonProcessingException, UnsupportedEncodingException;
OauthUserDto getUserInfo(String accessToken) throws JsonProcessingException;
User registerUserIfNeeded(OauthUserDto oauthTokenDto);
}
interface형식으로 만들어뒀다. 소셜 로그인(카카오, 네이버, 구글)을 할 때 각각 오버라이딩 해서 사용할 것이기 때문에 추가해 줬다.
5. 구글 서비스 설정
나는 application.properties를 사용하기 때문에 내부에 클라이언트 id, 클라이언트 비밀번호, 리다이렉트 url을 미리 넣어줬다.
@Service
@RequiredArgsConstructor
public class GoogleService implements OauthService{
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final RestTemplate restTemplate;
private final JwtUtil jwtUtil;
@Value("${google.client.id}")
private String CLIENT_ID;
@Value("${google.client.secret}")
private String SECRET_KEY;
@Value("${google.redirect.url}")
private String REDIRECT_URL;
@Override
public OauthTokenDto socialLogin(String code) throws JsonProcessingException{
// 1. "인가 코드"로 "액세스 토큰" 요청
String accessToken = getToken(code);
// 2. 토큰으로 카카오 API 호출 : "액세스 토큰"으로 "카카오 사용자 정보" 가져오기
OauthUserDto oauthUserDto = getUserInfo(accessToken);
// 3. 필요시에 회원가입
User googleUser = registerUserIfNeeded(oauthUserDto);
// 4. JWT 토큰 생성
String createToken = jwtUtil.createToken(googleUser.getUsername(), googleUser.getRole());
return new OauthTokenDto(createToken);
}
@Override
public String getToken(String code) throws JsonProcessingException{
// 요청 URL 만들기
URI uri = UriComponentsBuilder
.fromUriString("https://oauth2.googleapis.com")
.path("/token")
.encode()
.build()
.toUri();
// HTTP Header 생성
HttpHeaders headers = new HttpHeaders();
headers.add("Content-type", "application/x-www-form-urlencoded");
// HTTP Body 생성
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "authorization_code");
body.add("client_id", CLIENT_ID);
body.add("client_secret", SECRET_KEY);
body.add("redirect_uri", REDIRECT_URL); // 애플리케이션 등록시 설정한 redirect_uri
body.add("code", code);
// 방법 1
ResponseEntity<String> response = restTemplate.postForEntity(uri,new HttpEntity<>(body, headers),String.class);
// HTTP 응답 (JSON) -> 액세스 토큰 값을 반환합니다.
JsonNode jsonNode = new ObjectMapper().readTree(response.getBody());
return jsonNode.get("access_token").asText();
}
@Override
public OauthUserDto getUserInfo(String accessToken) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
HttpEntity<?> entity = new HttpEntity<>(headers);
ResponseEntity<OauthUserDto> response = restTemplate.exchange(
"https://www.googleapis.com/oauth2/v2/userinfo",
HttpMethod.GET,
entity,
OauthUserDto.class
);
OauthUserDto userInfo = response.getBody();
return userInfo;
}
@Override
public User registerUserIfNeeded(OauthUserDto apiUserInfoDto) {
// DB 에 중복된 구글 Id 가 있는지 확인
String googleId = apiUserInfoDto.getId();
User googleUser = userRepository.findByGoogleId(googleId).orElse(null);
if (googleUser == null) {
// 구글 사용자 email 동일한 email 가진 회원이 있는지 확인
String googleEmail = apiUserInfoDto.getEmail();
User sameEmailUser = userRepository.findByUsername(googleEmail).orElse(null);
if (sameEmailUser != null) {
googleUser = sameEmailUser;
// 기존 회원정보에 구글 Id 추가
googleUser = googleUser.googleIdUpdate(googleId);
} else {
// 신규 회원가입
// password: random UUID
String password = UUID.randomUUID().toString();
String encodedPassword = passwordEncoder.encode(password);
String email = apiUserInfoDto.getEmail();
apiUserInfoDto.setNickname(email.substring(0,email.indexOf('@')));
googleUser = new User(apiUserInfoDto, encodedPassword, UserRoleEnum.USER);
googleUser.googleIdUpdate(googleId);
}
userRepository.save(googleUser);
}
return googleUser;
}
}
socialLogin - 소셜 로그인 메서드. 인가 코드를 넘겨주고 JWT 토큰을 반환받는다.
getToken - 인가 코드를 사용한 액세스 토큰 요청 메서드. 전달받은 인가 코드를 넘겨주고 액세스 토큰을 반환받는다.
getUserInfo - 인가 토큰을 통해 사용자 정보를 가져오는 메서드. 액세스 토큰을 넘겨주고 회원정보를 반환받는다.
registerUserIfNeeded - 구글 ID 정보로 회원가입을 해주는 메서드. 회원정보를 넘겨주고 User객체를 추가한다.
6. 컨트롤러 설정
@GetMapping("/user/google/callback")
public String googleLogin(@RequestParam String code, HttpServletResponse response) throws JsonProcessingException{
OauthTokenDto tokenDto = googleService.socialLogin(code);
jwtUtil.addJwtToCookie(tokenDto.getAccessToken(), response);
return "redirect:/";
}
GET매핑으로 받아올 것이고 주소는 설정해 둔 리다이렉션 주소와 일치하게 설정하면 된다.
매개변수는 RequestParam 형식으로 code를 받아오고, HttpServletResponse로 응답을 받아온다.
OauthTokenDto는 액세스토큰 정보를 가지고 있는 Dto이다.
여기에 googleService클래스의 socialLogin 메서드에 code값을 넣어준 뒤 액세스 토큰을 받아온다.
그 뒤 jwtUtil의 addJwtToCookie 메서드를 호출하여 JWT 토큰을 생성하고 응답의 쿠키에 추가한다.
넘겨주는 값은 액세스토큰값, 응답값이다.
7. 테스트 방법
https://accounts.google.com/o/oauth2/v2/auth?
client_id=본인의 client Id
&redirect_uri=본인의 redirect URI
&response_type=code&scope=email
위 코드를 넣어서 테스트해 보면 된다.
나는 버튼을 하나 만들어서 테스트했다.
<추가>
Spring Boot 소셜로그인(네이버) 구현법(Oauth2.0)
Oauth2.0 사용자가 애플리케이션 또는 웹 사이트에 로그인할 때 사용되는 프로토콜 중 하나. 이 프로토콜은 보안된 방식으로 사용자의 정보를 제공하고, 다른 웹 사이트나 애플리케이션에서 해당
ngwdeveloper.tistory.com
Spring Boot 소셜로그인(카카오) 구현법(Oauth2.0)
oauth2.0 사용자가 애플리케이션 또는 웹 사이트에 로그인할 때 사용되는 프로토콜 중 하나. 이 프로토콜은 보안된 방식으로 사용자의 정보를 제공하고, 다른 웹 사이트나 애플리케이션에서 해당
ngwdeveloper.tistory.com
'공부메모 & 오류해결 > Spring Boot' 카테고리의 다른 글
[Spring Boot + Redis] Spring Boot에서 리프레시 토큰 사용하기(Redis) (1) | 2023.10.17 |
---|---|
[Spring Boot + OAUTH2.0] Spring Boot 소셜로그인(네이버) 구현법(Oauth2.0) (0) | 2023.10.10 |
[Spring Boot + OAUTH2.0] Spring Boot 소셜로그인(카카오) 구현법(Oauth2.0) (1) | 2023.10.10 |
[Spring Boot + OAUTH2.0] 구글 소셜로그인을 위한 설정(Spring + Oauth2.0) (0) | 2023.10.09 |
[Spring Boot + OAUTH2.0] 네이버 소셜로그인을 위한 설정(Spring + Oauth2.0) (1) | 2023.10.09 |
남건욱's 공부기록