https://im-babycoder.tistory.com/entry/Swift-iOS-프로젝트-Google-Login-구현하기
[Swift] iOS 프로젝트 Google Login 구현하기
친구들과 같이 진행하는 프로젝트에 Google Login 기능을 넣기로 했다. https://developers.google.com/identity/sign-in/ios/start-integrating iOS 및 macOS용 Google 로그인 시작하기 | Authentication | Google Developers 이 페이지
im-babycoder.tistory.com
이 글에 이어서 SpringBoot 서버를 만들어봤다.
https://developers.google.com/identity/sign-in/ios/backend-auth
백엔드 서버로 인증 | Authentication | Google Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English 의견 보내기 백엔드 서버로 인증 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 백엔드
developers.google.com
방법은 역시나 구글 공식 문서 참고

LoginViewController.swift
var loginModel: LoginModel?
// SignIn Google Action
@IBAction func signInWithGoogle(_ sender: Any) {
GIDSignIn.sharedInstance.signIn(with: self.signInConfig, presenting: self) { user, error in
guard error == nil else { return }
guard let user = user else { return }
user.authentication.do { authentication, error in
guard error == nil else { return }
guard let authentication = authentication else { return }
let idToken = authentication.idToken
// 백엔드 서버로 idToken 전송
self.requestIdTokenAuth(idToken: idToken!)
}
// request 후 화면 이동 코드 생략
// if loginModel.joinYn == nil ... 등등
}
}
func requestIdTokenAuth(idToken: String) {
guard let postData = try? JSONEncoder().encode(["idToken" : idToken, "appType" : "ios"]) else { return }
let url = URL(string: "http://localhost:8080/test/login")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.httpBody = postData
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else { return }
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
do {
self.loginModel = try JSONDecoder().decode(LoginModel.self, from: data)
} catch {
print(error)
}
}
}
task.resume()
}
구글 로그인에 성공해서 idToken이 생성되면 이 값을 서버로 전송하는 requestIdTokenAuth 메소드를 만들었다.
Json 형식으로 idToken과 appType을 함께 담아서 httpBody에 실어 보냈다.
(appType은 현재 진행하는 프로젝트에서는 ios와 web 두 곳에서 구글 로그인 진입을 하기 때문에 만든 것)
서버에서 응답으로 보내주는 값은 LoginModel.swift Codable 구조체를 만들어서 받아왔다.(하단 참고)
GoogleSignInController.java
import java.util.Collections;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.util.Utils;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.openbible.cymply.demo.google.vo.GoogleSignInVO;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@RestController
public class GoogleSignInController {
// api/iosGoogleTest
@PostMapping("/test/login") // url 이름 잘 맞추기
public GoogleSignInRVO cymplyLogin(@RequestBody GoogleSignInPVO pvo) throws Exception {
GoogleSignInRVO resultVO = new GoogleSignInRVO();
HttpTransport transport = Utils.getDefaultTransport();
JsonFactory jsonFactory = Utils.getDefaultJsonFactory();
GoogleIdToken idToken = null;
if("ios".equals(pvo.getAppType())) {
// iOS 접속
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
.setAudience(Collections.singletonList("iOS_클라이언트_ID")).build();
idToken = verifier.verify(pvo.getIdToken());
} else {
// WEB 접속
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
.setAudience(Collections.singletonList("WEB_클라이언트_ID")).build();
idToken = verifier.verify(pvo.getIdToken());
}
if(idToken != null) {
Payload payload = idToken.getPayload();
String email = payload.getEmail();
System.out.println("login email : " + email);
// Email DB 조회 결과 setting (하드코딩)
resultVO.setJoinYN("N");
resultVO.setLoginYN("Y");
resultVO.setNickname(null);
} else {
System.out.println("Invalid ID token.");
}
return resultVO;
}
}
payload를 사용해서 email 외에도 이름 등등 로그인한 유저의 정보를 받아올 수 있다.(공식 문서 참고)
로그인한 유저 정보를 DB 조회를 해서 이 유저가 서비스에 회원가입 했는지, 닉네임은 설정했는지 등등
결과를 VO에 담아서 리턴해준다.
보통 Controller에 이 모든 로직을 담지 않고 Service단으로 나누는데 일단 테스트니까 Controller에 모두 구현했다.
이 리턴한 VO는 Swift에서 다시 JSON 형태로 받아 사용할 수 있다.
ParameterVO
ios나 web 클라이언트에서 서버가 받는 객체 VO
import lombok.Data;
@Data
public class GoogleSignInPVO {
private String idToken;
private String appType;
}
Lombok @Data 어노테이션으로 변수 선언만으로도 Getter, Setter 메소드를 사용할 수 있게 했다.
다시 클라이언트로 응답을 보낼 VO도 위와 같이 만들어서 응답 값을 담아서 return해주면 된다.
Return Result VO
import lombok.Data;
@Data
public class GoogleSignInPVO {
private String joinYn;
private String loginYn;
private String nickname;
}
자바에서 이 객체들에 값을 담아 보낸다면
클라이언트에서도 이름을 잘 맞춰서 가져올 수 있게 해야한다.
LoginModel.swift
import Foundation
struct LoginModel: Codable {
let joinYn: String
let loginYn: String
let nickname: String?
}
응답으로 받은 Data를 Model에 담아 다시 ios 클라이언트에서 사용할 수 있다.
iOS에서 Request 요청이 안 보내진다면
이걸 추가해서 HTTP 통신 가능하게 해야된다.
'DEV - iOS > iOS' 카테고리의 다른 글
[SwiftUI] 설정화면 Form으로 만들어보기 (0) | 2024.05.23 |
---|---|
[Swift] iOS 프로젝트 Google Login 구현하기 (0) | 2022.10.22 |
[Swift] FSCalendar 라이브러리로 달력 구현하기-1(설치) (0) | 2022.08.08 |
[Swift / SpringBoot] WebView로 SpringBoot 서버 화면 띄우기 (0) | 2022.08.02 |
[Swift] Firebase Firestore 데이터 저장하기(이메일 중복 검사) (0) | 2022.05.21 |