Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Expand Up @@ -3,6 +3,8 @@
import dmu.dasom.api.domain.common.exception.ErrorResponse;
import dmu.dasom.api.domain.member.dto.SignupRequestDto;
import dmu.dasom.api.domain.member.service.MemberService;
import dmu.dasom.api.global.auth.dto.TokenBox;
import dmu.dasom.api.global.auth.userdetails.UserDetailsImpl;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
Expand All @@ -11,11 +13,10 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
Expand All @@ -39,16 +40,32 @@ public class MemberController {
),
@ExampleObject(
name = "이메일 또는 비밀번호 형식 올바르지 않음",
value = "{ \"code\": \"C007\", \"message\": \"요청한 값이 올바르지 않습니다.\" }"
)
}
)
)
})
value = "{ \"code\": \"C007\", \"message\": \"요청한 값이 올바르지 않습니다.\" }")}))})
@PostMapping("/auth/signup")
public ResponseEntity<Void> signUp(@Valid @RequestBody final SignupRequestDto request) {
memberService.signUp(request);
return ResponseEntity.ok().build();
}

@Operation(summary = "토큰 갱신")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "토큰 갱신 성공 (Header로 토큰 반환)"),
@ApiResponse(responseCode = "400", description = "실패 케이스",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(
name = "RefreshToken 만료",
value = "{ \"code\": \"C004\", \"message\": \"토큰이 만료되었습니다.\" }")}))})
@GetMapping("/auth/rotation")
public ResponseEntity<Void> tokenRotation(@AuthenticationPrincipal final UserDetailsImpl userDetails) {
final TokenBox tokenBox = memberService.tokenRotation(userDetails);
final HttpHeaders headers = new HttpHeaders();
headers.add("Access-Token", tokenBox.getAccessToken());
headers.add("Refresh-Token", tokenBox.getRefreshToken());

return ResponseEntity.ok().headers(headers).build();
}

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

import dmu.dasom.api.domain.member.dto.SignupRequestDto;
import dmu.dasom.api.domain.member.entity.Member;
import dmu.dasom.api.global.auth.dto.TokenBox;
import dmu.dasom.api.global.auth.userdetails.UserDetailsImpl;

public interface MemberService {

Expand All @@ -11,4 +13,6 @@ public interface MemberService {

void signUp(final SignupRequestDto request);

TokenBox tokenRotation(final UserDetailsImpl userDetails);

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import dmu.dasom.api.domain.member.dto.SignupRequestDto;
import dmu.dasom.api.domain.member.entity.Member;
import dmu.dasom.api.domain.member.repository.MemberRepository;
import dmu.dasom.api.global.auth.dto.TokenBox;
import dmu.dasom.api.global.auth.jwt.JwtUtil;
import dmu.dasom.api.global.auth.userdetails.UserDetailsImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
Expand All @@ -17,6 +20,7 @@ public class MemberServiceImpl implements MemberService {

private final BCryptPasswordEncoder encoder;
private final MemberRepository memberRepository;
private final JwtUtil jwtUtil;

// 이메일로 사용자 조회
@Override
Expand All @@ -42,4 +46,10 @@ public void signUp(final SignupRequestDto request) {
memberRepository.save(request.toEntity(encoder.encode(request.getPassword())));
}

// 토큰 갱신
@Override
public TokenBox tokenRotation(final UserDetailsImpl userDetails) {
return jwtUtil.tokenRotation(userDetails);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public SecurityFilterChain filterChain(final HttpSecurity http, final Authentica
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/admin/**").hasRole(Role.ROLE_ADMIN.getName())
.requestMatchers("/api/auth/logout").authenticated()
.requestMatchers("/api/auth/logout", "/api/auth/rotation").authenticated()
.anyRequest().permitAll())
.addFilterBefore(jwtFilter, CustomAuthenticationFilter.class)
.addFilterAt(customAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/dmu/dasom/api/global/auth/jwt/JwtUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import dmu.dasom.api.domain.common.exception.CustomException;
import dmu.dasom.api.domain.common.exception.ErrorCode;
import dmu.dasom.api.global.auth.dto.TokenBox;
import dmu.dasom.api.global.auth.userdetails.UserDetailsImpl;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.beans.factory.annotation.Value;
Expand Down Expand Up @@ -130,4 +131,10 @@ public boolean isExpired(final String token) {
}
}

// Access, Refresh 토큰 갱신
public TokenBox tokenRotation(final UserDetailsImpl userDetails) {
blacklistTokens(userDetails.getUsername());
return generateTokenBox(userDetails.getUsername());
}

}