Skip to content

Commit

Permalink
feat: 익명 로그인 API 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
peeerr committed Nov 4, 2024
1 parent d6e5ad3 commit 77f8ab4
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/members/login", "/h2-console/**", "/error", "/favicon.ico").permitAll()
.requestMatchers("/api/members/login", "/api/members/anonymous-login", "/h2-console/**",
"/error", "/favicon.ico").permitAll()
.requestMatchers("/swagger-resources/**", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
.anyRequest().authenticated());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ private OpenApiCustomizer addSecurityItemToAllEndpointsExceptLogin() {
return openApi -> {
SecurityRequirement securityRequirement = new SecurityRequirement().addList("bearerAuth");
openApi.getPaths().forEach((path, item) -> {
if (!"/api/members/login".equals(path)) {
if (!"/api/members/login".equals(path) && !"/api/members/anonymous-login".equals(path)) {
item.readOperations().forEach(operation -> {
operation.addSecurityItem(securityRequirement);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.potatocake.everymoment.dto.SuccessResponse;
import com.potatocake.everymoment.dto.request.MemberLoginRequest;
import com.potatocake.everymoment.dto.response.AnonymousLoginResponse;
import com.potatocake.everymoment.dto.response.JwtResponse;
import com.potatocake.everymoment.dto.response.MemberDetailResponse;
import com.potatocake.everymoment.dto.response.MemberMyResponse;
Expand Down Expand Up @@ -39,6 +40,15 @@ public class MemberController {

private final MemberService memberService;

@Operation(summary = "익명 로그인", description = "회원번호로 로그인하거나 새로운 익명 계정을 생성합니다.")
@ApiResponse(responseCode = "200", description = "익명 로그인 성공")
@GetMapping("/anonymous-login")
public ResponseEntity<SuccessResponse> anonymousLogin(@Parameter(description = "기기에 저장된 회원번호 (없을 경우 새로운 계정 생성)")
@RequestParam(required = false) Long number) {
AnonymousLoginResponse response = memberService.anonymousLogin(number);
return ResponseEntity.ok(SuccessResponse.ok(response));
}

@Operation(summary = "로그인", description = "회원 번호와 닉네임으로 로그인합니다.")
@ApiResponse(responseCode = "200", description = "로그인 성공", content = @Content(schema = @Schema(implementation = JwtResponse.class)))
@PostMapping("/login")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.potatocake.everymoment.dto.response;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Builder;
import lombok.Getter;

@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
@Getter
public class AnonymousLoginResponse {

private Long number;
private String token;

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.potatocake.everymoment.repository;

import com.potatocake.everymoment.entity.Member;
import jakarta.persistence.LockModeType;
import java.util.Optional;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Window;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;

public interface MemberRepository extends JpaRepository<Member, Long> {

Expand All @@ -15,4 +18,8 @@ public interface MemberRepository extends JpaRepository<Member, Long> {

Window<Member> findByNicknameContaining(String nickname, ScrollPosition position, Pageable pageable);

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT CASE WHEN MIN(m.number) > 0 OR MIN(m.number) IS NULL THEN -1 ELSE MIN(m.number) - 1 END FROM Member m")
Long findNextAnonymousNumber();

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static org.springframework.data.domain.Sort.Direction.ASC;

import com.potatocake.everymoment.dto.response.AnonymousLoginResponse;
import com.potatocake.everymoment.dto.response.FriendRequestStatus;
import com.potatocake.everymoment.dto.response.MemberDetailResponse;
import com.potatocake.everymoment.dto.response.MemberMyResponse;
Expand All @@ -13,6 +14,7 @@
import com.potatocake.everymoment.repository.FriendRepository;
import com.potatocake.everymoment.repository.FriendRequestRepository;
import com.potatocake.everymoment.repository.MemberRepository;
import com.potatocake.everymoment.util.JwtUtil;
import com.potatocake.everymoment.util.PagingUtil;
import com.potatocake.everymoment.util.S3FileUploader;
import java.util.List;
Expand All @@ -35,6 +37,7 @@ public class MemberService {
private final FriendRepository friendRepository;
private final PagingUtil pagingUtil;
private final S3FileUploader s3FileUploader;
private final JwtUtil jwtUtil;

@Transactional(readOnly = true)
public MemberSearchResponse searchMembers(String nickname, Long key, int size, Long currentMemberId) {
Expand Down Expand Up @@ -72,6 +75,39 @@ public MemberMyResponse getMemberInfo(Long memberId) {
.build();
}

public AnonymousLoginResponse anonymousLogin(Long memberNumber) {
if (memberNumber != null) {
// 기존 회원번호로 로그인 시도
return memberRepository.findByNumber(memberNumber)
.map(member -> AnonymousLoginResponse.builder()
.token(jwtUtil.create(member.getId()))
.build())
.orElseGet(this::createAnonymousLoginResponse);
}

// 새로운 익명 회원 생성 및 응답
return createAnonymousLoginResponse();
}

private AnonymousLoginResponse createAnonymousLoginResponse() {
Member newMember = createAnonymousMember();
return AnonymousLoginResponse.builder()
.number(newMember.getNumber())
.token(jwtUtil.create(newMember.getId()))
.build();
}

private Member createAnonymousMember() {
Long nextNumber = memberRepository.findNextAnonymousNumber();

Member member = Member.builder()
.nickname("Anonymous")
.number(nextNumber)
.build();

return memberRepository.save(member);
}

public void updateMemberInfo(Long id, MultipartFile profileImage, String nickname) {
Member member = memberRepository.findById(id)
.orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND));
Expand Down

0 comments on commit 77f8ab4

Please sign in to comment.