Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] 로그아웃 api #94

Merged
merged 4 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package com.soptie.server.auth.controller;

import com.soptie.server.auth.dto.SignInRequest;
import com.soptie.server.auth.message.ResponseMessage;
import com.soptie.server.auth.service.AuthService;
import com.soptie.server.common.dto.Response;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;

import static com.soptie.server.auth.message.ResponseMessage.*;
import static com.soptie.server.common.dto.Response.success;

@RestController
Expand All @@ -21,6 +23,13 @@ public class AuthController {
@PostMapping
public ResponseEntity<Response> signIn(@RequestHeader("Authorization") String socialAccessToken, @RequestBody SignInRequest request) {
val response = authService.signIn(socialAccessToken, request);
return ResponseEntity.ok(success(ResponseMessage.SUCCESS_SIGNIN.getMessage(), response));
return ResponseEntity.ok(success(SUCCESS_SIGN_IN.getMessage(), response));
}

@PostMapping("/logout")
public ResponseEntity<Response> signOut(Principal principal) {
val memberId = Long.parseLong(principal.getName());
authService.signOut(memberId);
return ResponseEntity.ok(success(SUCCESS_SIGN_OUT.getMessage(), null));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
@Getter
public enum ResponseMessage {

SUCCESS_SIGNIN("소셜로그인 성공");
SUCCESS_SIGN_IN("소셜로그인 성공"),
SUCCESS_SIGN_OUT("로그아웃 성공"),
;

private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
public interface AuthService {

SignInResponse signIn(String socialAccessToken, SignInRequest request);
void signOut(Long memberId);
}
14 changes: 14 additions & 0 deletions src/main/java/com/soptie/server/auth/service/AuthServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import com.soptie.server.member.entity.Member;
import com.soptie.server.member.entity.SocialType;
import com.soptie.server.member.repository.MemberRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.soptie.server.auth.message.ErrorMessage.INVALID_TOKEN;
import static com.soptie.server.member.message.ErrorMessage.INVALID_MEMBER;

@Service
@RequiredArgsConstructor
Expand All @@ -33,6 +35,13 @@ public SignInResponse signIn(String socialAccessToken, SignInRequest request) {
return SignInResponse.of(getToken(getMember(socialAccessToken, request)));
}

@Override
@Transactional
public void signOut(Long memberId) {
Member member = findMember(memberId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

val 타입 부탁드려요 :)

member.updateRefreshToken(null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null을 인자로 넘기는 것도 좋지만, initRefreshToken 메소드를 별도로 만들고 내부에서 null로 처리해도 좋을 것 같아요!

}

private Member getMember(String socialAccessToken, SignInRequest request) {
val socialType = request.socialType();
val socialId = getSocialId(socialAccessToken, socialType);
Expand Down Expand Up @@ -71,4 +80,9 @@ private Token generateToken(Authentication authentication) {
.refreshToken(jwtTokenProvider.generateToken(authentication, valueConfig.getRefreshTokenExpired()))
.build();
}

private Member findMember(Long id) {
return memberRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException(INVALID_MEMBER.getMeesage()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,5 @@ public ResponseEntity<Response> getMemberHomeInfo(Principal principal) {
val memberId = Long.parseLong(principal.getName());
val memberHomeInfoResponse = memberService.getMemberHomeInfo(memberId);
return ResponseEntity.ok(success(SUCCESS_HOME_INFO.getMessage(), memberHomeInfoResponse));

}
}
35 changes: 28 additions & 7 deletions src/main/resources/static/docs/open-api-3.0.1.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@
"content" : {
"application/json;charset=UTF-8" : {
"schema" : {
"$ref" : "#/components/schemas/api-v1-members935091773"
"$ref" : "#/components/schemas/api-v1-members-980081866"
},
"examples" : {
"get-member-home-screen-docs" : {
"value" : "{\r\n \"success\" : true,\r\n \"message\" : \"홈 화면 불러오기 성공\",\r\n \"data\" : {\r\n \"name\" : \"softie\",\r\n \"dollType\" : \"BROWN\",\r\n \"attentionImageUrl\" : \"attentionImageUrl\",\r\n \"frameImageUrl\" : \"frameImageUrl\",\r\n \"dailyCottonCount\" : 0,\r\n \"happinessCottonCount\" : 0,\r\n \"conversations\" : [ \"안녕\", \"하이\", \"봉쥬르\" ]\r\n }\r\n}"
"value" : "{\r\n \"success\" : true,\r\n \"message\" : \"홈 화면 불러오기 성공\",\r\n \"data\" : {\r\n \"name\" : \"softie\",\r\n \"dollType\" : \"BROWN\",\r\n \"frameImageUrl\" : \"frameImageUrl\",\r\n \"dailyCottonCount\" : 0,\r\n \"happinessCottonCount\" : 0,\r\n \"conversations\" : [ \"안녕\", \"하이\", \"봉쥬르\" ]\r\n }\r\n}"
}
}
}
Expand Down Expand Up @@ -154,6 +154,31 @@
}
}
},
"/api/v1/auth/logout" : {
"post" : {
"tags" : [ "AUTH" ],
"summary" : "로그아웃",
"description" : "로그아웃",
"operationId" : "post-logout-docs",
"responses" : {
"200" : {
"description" : "200",
"content" : {
"application/json;charset=UTF-8" : {
"schema" : {
"$ref" : "#/components/schemas/api-v1-members594740350"
},
"examples" : {
"post-logout-docs" : {
"value" : "{\r\n \"success\" : true,\r\n \"message\" : \"로그아웃 성공\",\r\n \"data\" : null\r\n}"
}
}
}
}
}
}
}
},
"/api/v1/members/{cottonType}" : {
"patch" : {
"tags" : [ "MEMBER" ],
Expand Down Expand Up @@ -479,7 +504,7 @@
},
"components" : {
"schemas" : {
"api-v1-members935091773" : {
"api-v1-members-980081866" : {
"type" : "object",
"properties" : {
"data" : {
Expand All @@ -493,10 +518,6 @@
"type" : "string",
"description" : "인형 이름"
},
"attentionImageUrl" : {
"type" : "string",
"description" : "인형 이미지 url"
},
"frameImageUrl" : {
"type" : "string",
"description" : "인형 배경 이미지 url"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders;

import java.security.Principal;

import static com.epages.restdocs.apispec.ResourceDocumentation.resource;
import static com.soptie.server.auth.message.ResponseMessage.SUCCESS_SIGN_IN;
import static com.soptie.server.auth.message.ResponseMessage.SUCCESS_SIGN_OUT;
import static org.mockito.Mockito.when;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.*;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.payload.JsonFieldType.*;
Expand All @@ -31,6 +36,8 @@ class AuthControllerTest extends BaseControllerTest {

@MockBean
AuthController controller;
@MockBean
Principal principal;

private final String DEFAULT_URL = "/api/v1/auth";
private final String TAG = "AUTH";
Expand All @@ -47,15 +54,15 @@ void success_getTokenBySocialAccessToken() throws Exception {
.refreshToken("token")
.build()
);
ResponseEntity<Response> result = ResponseEntity.ok(Response.success("소셜로그인 성공", response));
ResponseEntity<Response> result = ResponseEntity.ok(Response.success(SUCCESS_SIGN_IN.getMessage(), response));

// when
when(controller.signIn(socialAccessToken, request)).thenReturn(result);

// then
mockMvc
.perform(
RestDocumentationRequestBuilders.post(DEFAULT_URL)
post(DEFAULT_URL)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.header("Authorization", socialAccessToken)
Expand Down Expand Up @@ -84,4 +91,39 @@ void success_getTokenBySocialAccessToken() throws Exception {
.build())))
.andExpect(status().isOk());
}

@Test
@DisplayName("로그아웃 성공")
void success_signOut() throws Exception {
// given
ResponseEntity<Response> result = ResponseEntity.ok(Response.success(SUCCESS_SIGN_OUT.getMessage(), null));

// when
when(controller.signOut(principal)).thenReturn(result);

// then
mockMvc
.perform(
post(DEFAULT_URL + "/logout")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.principal(principal)
)
.andDo(
MockMvcRestDocumentation.document(
"post-logout-docs",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint()),
resource(
ResourceSnippetParameters.builder()
.tag(TAG)
.description("로그아웃")
.responseFields(
fieldWithPath("success").type(BOOLEAN).description("응답 성공 여부"),
fieldWithPath("message").type(STRING).description("응답 메시지"),
fieldWithPath("data").type(NULL).description("응답 데이터")
)
.build())))
.andExpect(status().isOk());
}
}