Skip to content

Commit

Permalink
[feat] kakao social login 구현
Browse files Browse the repository at this point in the history
[feat] kakao social login 구현
  • Loading branch information
bo-ram-bo-ram authored Jul 7, 2024
2 parents 43e0c08 + 03f0f71 commit 4d7bf8e
Show file tree
Hide file tree
Showing 41 changed files with 1,051 additions and 119 deletions.
73 changes: 46 additions & 27 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,53 +1,72 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.7'
id 'io.spring.dependency-management' version '1.1.5'
id 'java'
id 'org.springframework.boot' version '3.2.7'
id 'io.spring.dependency-management' version '1.1.5'
}

group = 'com.pickple'
version = '0.0.1-SNAPSHOT'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
// Spring
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Spring
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
implementation 'org.springframework.boot:spring-boot-starter-actuator'

//db
implementation group: 'org.postgresql', name: 'postgresql', version: '42.7.3'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
//db
implementation group: 'org.postgresql', name: 'postgresql', version: '42.7.3'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'


// Lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// Lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

// Validation
implementation 'org.springframework.boot:spring-boot-starter-validation'
// Validation
implementation 'org.springframework.boot:spring-boot-starter-validation'

// Test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// Test
testImplementation 'org.springframework.boot:spring-boot-starter-test'

//junit
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
//junit
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

//External API
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.0'

//Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'


//JWT
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'

//Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis:3.2.1'

//Security
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
}

tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package com.pickple.server;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;

@EnableFeignClients
@SpringBootApplication
@ImportAutoConfiguration(FeignAutoConfiguration.class)
public class PickpleServerApplication {

public static void main(String[] args) {
Expand Down
57 changes: 0 additions & 57 deletions src/main/java/com/pickple/server/api/TestController.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.pickple.server.api.user.controller;

import com.pickple.server.api.user.dto.AccessTokenGetSuccess;
import com.pickple.server.api.user.dto.LoginSuccessResponse;
import com.pickple.server.api.user.service.UserService;
import com.pickple.server.global.auth.client.dto.UserLoginRequest;
import com.pickple.server.global.auth.jwt.service.TokenService;
import com.pickple.server.global.response.ApiResponseDto;
import com.pickple.server.global.response.enums.SuccessCode;
import java.security.Principal;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class UserController implements UserControllerDocs {

private final UserService userService;
private final TokenService tokenService;

@PostMapping("api/v1/user/login")
@Override
public ApiResponseDto<LoginSuccessResponse> login(
@RequestParam final String authorizationCode,
@RequestBody final UserLoginRequest loginRequest
) {
return ApiResponseDto.success(SuccessCode.LOGIN_SUCCESS, userService.create(authorizationCode, loginRequest));
}

@GetMapping("api/v1/user/token-refresh")
@Override
public ApiResponseDto<AccessTokenGetSuccess> refreshToken(
@RequestParam final String refreshToken
) {
return ApiResponseDto.success(SuccessCode.ISSUE_ACCESS_TOKEN_SUCCESS, userService.refreshToken(refreshToken));
}

@DeleteMapping("api/v1/user/delete")
@Override
public ApiResponseDto deleteUser(
final Principal principal
) {
tokenService.deleteRefreshToken(Long.valueOf(principal.getName()));
userService.deleteUser(Long.valueOf(principal.getName()));
return ApiResponseDto.success(SuccessCode.USER_DELETE_SUCCESS);
}

@PostMapping("api/v1/user/logout")
@Override
public ApiResponseDto logout(
final Principal principal
) {
tokenService.deleteRefreshToken(Long.valueOf(principal.getName()));
return ApiResponseDto.success(SuccessCode.LOGOUT_SUCCESS);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.pickple.server.api.user.controller;


import com.pickple.server.api.user.dto.AccessTokenGetSuccess;
import com.pickple.server.api.user.dto.LoginSuccessResponse;
import com.pickple.server.global.auth.client.dto.UserLoginRequest;
import com.pickple.server.global.response.ApiResponseDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.security.Principal;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

@Tag(name = "User", description = "User 관련 API")
public interface UserControllerDocs {
@Operation(summary = "소셜 로그인")
@ApiResponses(
value = {
@ApiResponse(responseCode = "200", description = "소셜 로그인이 완료되었습니다."),
@ApiResponse(responseCode = "400", description =
"1. 요청한 값이 유효하지 않습니다.\n" + "2. 인가 코드가 만료되었습니다.\n"),
@ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.")
}
)
ApiResponseDto<LoginSuccessResponse> login(
@RequestParam final String authorizationCode,
@RequestBody final UserLoginRequest loginRequest
);

@Operation(summary = "액세스 토큰 재발급")
@ApiResponses(
value = {
@ApiResponse(responseCode = "200", description = "액세스 토큰 재발급이 완료되었습니다."),
@ApiResponse(responseCode = "401", description = "리프레시 토큰이 유효하지 않습니다."),
@ApiResponse(responseCode = "404", description = "해당 유저의 리프레시 토큰이 존재하지 않습니다."),
@ApiResponse(responseCode = "500", description = "서버 내부 오류입니다.")
}
)
ApiResponseDto<AccessTokenGetSuccess> refreshToken(
@RequestParam final String refreshToken
);

@Operation(summary = "회원 탈퇴")
@ApiResponses(
value = {
@ApiResponse(responseCode = "200", description = "회원 삭제가 완료되었습니다."),
@ApiResponse(responseCode = "404", description =
"1. 해당 유저의 리프레시 토큰이 존재하지 않습니다.\n" +
"2. 해당 유저는 존재하지 않습니다."
)
}
)
ApiResponseDto deleteUser(
final Principal principal
);

@Operation(summary = "로그아웃")
@ApiResponses(
value = {
@ApiResponse(responseCode = "200", description = "로그아웃이 완료되었습니다."),
@ApiResponse(responseCode = "404", description = "해당 유저의 리프레시 토큰이 존재하지 않습니다.")
}
)
ApiResponseDto logout(
Principal principal
);
}
12 changes: 12 additions & 0 deletions src/main/java/com/pickple/server/api/user/domain/SocialType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.pickple.server.api.user.domain;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum SocialType {
KAKAO("KAKAO"),
;
private String type;
}
49 changes: 49 additions & 0 deletions src/main/java/com/pickple/server/api/user/domain/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.pickple.server.api.user.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@Table(name = "users")
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private Long socialId;

private String email;

@Enumerated(EnumType.STRING)
private SocialType socialType;

private String socialNickname;

public static User of(
final Long socialId,
final String email,
final SocialType socialType,
final String socialNickname
) {
return User.builder()
.socialId(socialId)
.email(email)
.socialType(socialType)
.socialNickname(socialNickname)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.pickple.server.api.user.dto;

public record AccessTokenGetSuccess(
String accessToken
) {
public static AccessTokenGetSuccess of(
final String accessToken
) {
return new AccessTokenGetSuccess(accessToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.pickple.server.api.user.dto;

public record LoginSuccessResponse(
String accessToken,
String refreshToken
) {
public static LoginSuccessResponse of(
final String accessToken,
final String refreshToken
) {
return new LoginSuccessResponse(accessToken, refreshToken);
}
}
Loading

0 comments on commit 4d7bf8e

Please sign in to comment.