Skip to content

Commit

Permalink
#294 feat:애플 회원가입, 로그인API- 다른 프로젝트에서 가져옴. 추후 최적화 필요
Browse files Browse the repository at this point in the history
  • Loading branch information
xhaktmchl committed Jan 29, 2023
1 parent 7ebb7c0 commit b7a2136
Show file tree
Hide file tree
Showing 27 changed files with 1,403 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ out/

### VS Code ###
.vscode/

#추가
AuthKey_QLHFNT37VK.p8
application.properties
17 changes: 17 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,29 @@ dependencies {
//mongodb
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

// apple login
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' // 테스트 용
implementation 'org.apache.httpcomponents:httpclient'
implementation 'com.nimbusds:nimbus-jose-jwt:3.10'
implementation "io.jsonwebtoken:jjwt:0.9.1"
implementation "org.bouncycastle:bcpkix-jdk15on:1.50"
implementation "org.apache.httpcomponents:httpclient:4.5.13"
implementation fileTree(dir: 'libs', include: '*.jar')
}

tasks.named('test') {
useJUnitPlatform()
}

// apple login
tasks.withType(JavaCompile){
options.compilerArgs.addAll([
"--add-exports=java.base/sun.security.pkcs=ALL-UNNAMED",
"--add-exports=java.base/sun.security.util=ALL-UNNAMED",
"--add-exports=java.base/sun.security.x509=ALL-UNNAMED"
])
}

//Querydsl 추가, 자동 생성된 Q클래스 gradle clean으로 제거
clean {
delete file('src/main/generated')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ public enum BaseResponseStatus {
ALREADY_PARTICIPATE_CHATROOM(false, 2209, "이미 채팅방에 참여하고 있습니다."),
NOT_EXISTS_CHAT(false,2210,"채팅이 존재하지 않습니다."),
EXCEEDED_IMAGE(false,2211,"이미지 갯수를 초과했습니다."),
INVALID_APPLE_REFRESHTOKEN(false, 2212, "올바르지 않은 애플 리프레시 토큰입니다."),



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

public enum MemberLoginType {
NORMAL_USER("일반 로그인 유저"),
NAVER_USER("네이버 로그인 유저");
NAVER_USER("네이버 로그인 유저"),
APPLE_USER("애플 로그인 유저");

private String description;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package shop.geeksasang.controller.applelogin.controller;

import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import shop.geeksasang.config.response.BaseResponse;
import shop.geeksasang.controller.applelogin.model.*;
import shop.geeksasang.controller.applelogin.service.AppleService;

import java.security.NoSuchAlgorithmException;

@Controller
public class AppleController {

private Logger logger = LoggerFactory.getLogger(AppleController.class);

@Autowired
AppleService appleService;

/**
* Apple 회원가입
* privateKey 로 사용자 개인 정보와 refreshToken 발급받기
* @return
*/
@ApiOperation(value = "회원가입")
@PostMapping(value = "/sign-up/apple")
@ResponseBody
public BaseResponse<TokenResponse> signUpApple(@RequestBody ServicesResponse servicesResponse) throws NoSuchAlgorithmException {

if (servicesResponse == null) { // TODO 예외처리
System.out.println("요청 값이 없습니다.");
return null;
}
TokenResponse tokenResponse = appleService.requestCodeValidations(servicesResponse, null);
return new BaseResponse<>(tokenResponse);
}

/**
* Apple 로그인
*
* @return
*/
@ApiOperation(value = "로그인")
@PostMapping(value = "/log-in/apple")
@ResponseBody
public BaseResponse<TokenResponse> logInApple(@RequestBody AppleLoginReq appleLoginReq) throws NoSuchAlgorithmException {

if (appleLoginReq == null) { // TODO 예외처리
System.out.println("요청 값이 없습니다.");
return null;
}
TokenResponse tokenResponse = appleService.requestCodeValidations(appleLoginReq.getServicesResponse(), appleLoginReq.getRefreshToken());
return new BaseResponse<>(tokenResponse);
}

/**
* Apple 계정 탈퇴
*
* @return
*/
@ApiOperation(value = "회원탈퇴")
@PostMapping(value = "/delete/apple")
@ResponseBody
public BaseResponse<String> deleteUserApple(@RequestBody DeleteUserReq deleteUserReq) throws NoSuchAlgorithmException {

appleService.deleteUser(deleteUserReq);

return new BaseResponse<>("애플 탈퇴를 성공했습니다.");
}

/**
* refresh_token 유효성 검사
*
* @param client_secret
* @param refresh_token
* @return
* refresh_token은 만료되지 않기 때문에
* 권한이 필요한 요청일 경우 굳이 매번 애플 ID 서버로부터 refresh_token을 통해 access_token을 발급 받기보다는
* 유저의 refresh_token을 따로 DB나 기타 저장소에 저장해두고 캐싱해두고 조회해서 검증하는편이 성능면에서 낫다고 함..
* 우리도 db에 refresh token을 따로 저장해서 사용하므로 이 메소드는 필요 없지 않을까..
*/
// @PostMapping(value = "/refresh")
// @ResponseBody
// public TokenResponse refreshRedirect(@RequestParam String client_secret, @RequestParam String refresh_token) {
// return appleService.requestCodeValidations(client_secret, null, refresh_token);
// }

/**
* Apple 유저의 이메일 변경, 서비스 해지, 계정 탈퇴에 대한 Notifications을 받는 Controller (SSL - https (default: 443))
*
* @param appsResponse
*/
@PostMapping(value = "/apps/to/endpoint")
@ResponseBody
public void appsToEndpoint(@RequestBody AppsResponse appsResponse) {
System.out.println("애플 계정 탈퇴했습니다.");
logger.debug("[/path/to/endpoint] RequestBody ‣ " + appsResponse.getPayload());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//package shop.geeksasang.controller.applelogin.exception;
//
//import org.springframework.http.HttpStatus;
//
//public class AppleLoginException extends ApplicationException {
//
// protected AppleLoginException(String errorCode, HttpStatus httpStatus, String message) {
// super(errorCode, httpStatus, message);
// }
//}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//package shop.geeksasang.controller.applelogin.exception;
//
//import lombok.Getter;
//import lombok.RequiredArgsConstructor;
//import org.springframework.http.HttpStatus;
//
//import static org.springframework.http.HttpStatus.NOT_FOUND;
//
//@Getter
//@RequiredArgsConstructor
//public enum AppleLoginExceptionList {
//
// NOT_FOUND_REFRESH_TOKEN("U0001", NOT_FOUND,"리프레쉬 토큰이 존재하지 않습니다. Apple 회원가입을 먼저 진행해주세요."),
// INVALID_REFRESH_TOKEN("U0002", NOT_FOUND,"올바르지 않은 리프레쉬 토큰 입니다.");
//
// private final String CODE;
// private final HttpStatus HTTPSTATUS;
// private final String MESSAGE;
//
//}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//package shop.geeksasang.controller.applelogin.exception;
//
//
//import static com.yogit.server.applelogin.exception.AppleLoginExceptionList.INVALID_REFRESH_TOKEN;
//
//public class InvalidRefreshTokenException extends AppleLoginException{
// public InvalidRefreshTokenException() {
// super(INVALID_REFRESH_TOKEN.getCODE(), INVALID_REFRESH_TOKEN.getHTTPSTATUS(), INVALID_REFRESH_TOKEN.getMESSAGE());
// }
//}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//package shop.geeksasang.controller.applelogin.exception;
//
//import static com.yogit.server.applelogin.exception.AppleLoginExceptionList.NOT_FOUND_REFRESH_TOKEN;
//
//public class NotFoundRefreshTokenException extends AppleLoginException{
// public NotFoundRefreshTokenException() {
// super(NOT_FOUND_REFRESH_TOKEN.getCODE(), NOT_FOUND_REFRESH_TOKEN.getHTTPSTATUS(), NOT_FOUND_REFRESH_TOKEN.getMESSAGE());
// }
//}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package shop.geeksasang.controller.applelogin.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.minidev.json.JSONObject;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Account {

private String state;
private String code; // authorization_token
private String id_token; // identity_token
private JSONObject user; // 애플에서 제공하는 유저 정보
private String identifier;
private Boolean hasRequirementInfo; // 유저 필수정보 입력 여부
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package shop.geeksasang.controller.applelogin.model;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class AppleLoginReq {

private ServicesResponse servicesResponse;

private String refreshToken; // 로그인 처리를 위한 token
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package shop.geeksasang.controller.applelogin.model;


public class AppsResponse {

private String payload;

public String getPayload() {
return payload;
}

public void setPayload(String payload) {
this.payload = payload;
}

public AppsResponse() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package shop.geeksasang.controller.applelogin.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class DeleteUserReq {
int userId;
String refreshToken;

String identityToken;
}
62 changes: 62 additions & 0 deletions src/main/java/shop/geeksasang/controller/applelogin/model/Key.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package shop.geeksasang.controller.applelogin.model;

public class Key {

private String kty;
private String kid;
private String use;
private String alg;
private String n;
private String e;

public String getKty() {
return kty;
}

public void setKty(String kty) {
this.kty = kty;
}

public String getKid() {
return kid;
}

public void setKid(String kid) {
this.kid = kid;
}

public String getUse() {
return use;
}

public void setUse(String use) {
this.use = use;
}

public String getAlg() {
return alg;
}

public void setAlg(String alg) {
this.alg = alg;
}

public String getN() {
return n;
}

public void setN(String n) {
this.n = n;
}

public String getE() {
return e;
}

public void setE(String e) {
this.e = e;
}

public Key() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package shop.geeksasang.controller.applelogin.model;

import java.util.List;

public class Keys {

private List<Key> keys;

public List<Key> getKeys() {
return keys;
}

public void setKeys(List<Key> keys) {
this.keys = keys;
}

public Keys() {
}
}
Loading

0 comments on commit b7a2136

Please sign in to comment.