Skip to content

Commit

Permalink
Merge: 시큐리티 긴급 픽스
Browse files Browse the repository at this point in the history
  • Loading branch information
juwon-code authored Nov 6, 2024
2 parents db51d77 + e980708 commit 508e99a
Show file tree
Hide file tree
Showing 35 changed files with 372 additions and 615 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class FeedController (
}

@PostMapping
fun create(requestDto: FeedRequestDto.Create): ResponseEntity<Map<String, Any>> {
fun create(@RequestBody requestDto: FeedRequestDto.Create): ResponseEntity<Map<String, Any>> {
return ResponseEntity.ok(mapOf(
"message" to "피드를 성공적으로 등록했습니다.",
"result" to feedService.save(requestDto)
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/org/tenten/bittakotlin/feed/entity/Feed.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ data class Feed(

@CreatedDate
@Column(updatable = false, nullable = false)
val createdAt: LocalDateTime? = null,
var createdAt: LocalDateTime? = null,

@LastModifiedDate
@Column(updatable = true, nullable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.tenten.bittakotlin.feed.entity.Feed
import org.tenten.bittakotlin.feed.entity.FeedMedia
import org.tenten.bittakotlin.feed.entity.key.FeedMediaId
import org.tenten.bittakotlin.feed.repository.FeedMediaRepository
import org.tenten.bittakotlin.media.dto.MediaRequestDto
import org.tenten.bittakotlin.media.dto.MediaResponseDto
Expand All @@ -22,10 +23,12 @@ class FeedMediaServiceImpl(

uploadRequestDtos.forEach { uploadRequestDto ->
val mediaResponseDto: MediaResponseDto.Upload = mediaService.upload(uploadRequestDto, profile)
val media = mediaResponseDto.media

feedMediaRepository.save(FeedMedia(
id = FeedMediaId(feedId = feed.id!!, mediaId = media.id!!),
feed = feed,
media = mediaResponseDto.media
media = media
))

responseDto.add(MediaResponseDto.Read(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.tenten.bittakotlin.feed.dto.FeedRequestDto
import org.tenten.bittakotlin.feed.dto.FeedResponseDto
import org.tenten.bittakotlin.profile.entity.Profile
import org.tenten.bittakotlin.profile.service.ProfileService
import java.time.LocalDateTime

@Service
@RequiredArgsConstructor
Expand Down Expand Up @@ -80,7 +81,9 @@ class FeedServiceImpl(
val feed: Feed = feedRepository.save(Feed(
title = requestDto.title,
content = requestDto.content,
profile = profile
profile = profile,
createdAt = LocalDateTime.now(),
updatedAt = LocalDateTime.now()
))

return if (requestDto.medias != null) {
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ data class Media (

@CreatedDate
@Column(nullable = false, updatable = false)
val savedAt: LocalDateTime? = null,
var savedAt: LocalDateTime? = null,

@ManyToOne
@JoinColumn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.access.AccessDeniedException
Expand All @@ -14,17 +17,55 @@ import org.tenten.bittakotlin.member.dto.MemberResponseDTO
import org.tenten.bittakotlin.member.exception.MemberException
import org.tenten.bittakotlin.member.repository.MemberRepository
import org.tenten.bittakotlin.member.service.MemberService
import org.tenten.bittakotlin.security.jwt.JWTUtil
import org.tenten.bittakotlin.security.util.JwtTokenUtil

@Tag(name = "회원관리 API 컨트롤러", description = "회원과 관련된 RestAPI 제공 컨트롤러")
@RestController
@RequestMapping("/api/v1/member")
class MemberController(
private val memberService: MemberService,
private val jwtUtil: JWTUtil,
private val memberRepository: MemberRepository
private val memberRepository: MemberRepository,
private val jwtTokenUtil: JwtTokenUtil
) {

@PostMapping("/login")
fun login(@RequestBody requestDto: MemberRequestDTO.Login): ResponseEntity<Map<String, Any>> {
val responseDto: MemberResponseDTO.Login = memberService.login(requestDto)

val headers = HttpHeaders().apply {
add(HttpHeaders.SET_COOKIE, getCookieString("accessToken", responseDto.accessToken, 3600, false))
add(HttpHeaders.SET_COOKIE, getCookieString("refreshToken", responseDto.refreshToken, 604800, false))
add(HttpHeaders.SET_COOKIE, getCookieString("profileId", responseDto.profileId.toString(), 604800, true))
add(HttpHeaders.SET_COOKIE, getCookieString("profileUrl", responseDto.profileUrl, 604800, true))
}

val body = mapOf("message" to "로그인이 성공했습니다.")

return ResponseEntity(body, headers, HttpStatus.OK)
}

@PostMapping("/logout")
fun logout(request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Map<String, Any>> {
val headers = HttpHeaders().apply {
add(HttpHeaders.SET_COOKIE, getCookieString("accessToken", null, 0, false))
add(HttpHeaders.SET_COOKIE, getCookieString("refreshToken", null, 0, false))
add(HttpHeaders.SET_COOKIE, getCookieString("profileId", null, 0, true))
add(HttpHeaders.SET_COOKIE, getCookieString("profileUrl", null, 0, true))
}

val body = mapOf("message" to "로그아웃이 성공했습니다.")

return ResponseEntity(body, headers, HttpStatus.OK)
}


private fun getCookieString(name: String, token: String?, ageMax: Int, isPublic: Boolean): String {
return buildString {
append("$name=$token; Path=/; Max-Age=$ageMax;")
if (!isPublic) append(" HttpOnly;")
}
}

// 회원가입

@Operation(
Expand Down Expand Up @@ -77,7 +118,7 @@ class MemberController(
@RequestHeader("access") token: String // JWT 토큰을 헤더에서 추출
): ResponseEntity<Void> {
// 현재 로그인한 사용자 username 추출
val usernameFromToken = jwtUtil.getUsername(token)
val usernameFromToken = jwtTokenUtil.getUsername(token)

// id로 회원 정보 조회
val member = memberRepository.findById(id)
Expand All @@ -96,7 +137,7 @@ class MemberController(

@DeleteMapping("/{id}")
fun remove(@PathVariable id: Long, @RequestHeader("access") token: String): ResponseEntity<String> {
val username = jwtUtil.getUsername(token)
val username = jwtTokenUtil.getUsername(token)
val member = memberRepository.findById(id)
.orElseThrow { IllegalArgumentException("Member not Found.") }
if(member.username != username) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,13 @@ class MemberResponseDTO {
val address: String
)

data class Login(
val accessToken: String,

val refreshToken: String,

val profileId: Long,

val profileUrl: String
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.tenten.bittakotlin.member.dto.MemberRequestDTO
import org.tenten.bittakotlin.member.dto.MemberResponseDTO

interface MemberService {
fun login(requestDto: MemberRequestDTO.Login): MemberResponseDTO.Login

fun join(joinDTO: MemberRequestDTO.Join) // Join 기능 병합

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,43 @@ import org.tenten.bittakotlin.member.dto.MemberResponseDTO
import org.tenten.bittakotlin.member.entity.Member
import org.tenten.bittakotlin.member.exception.MemberException
import org.tenten.bittakotlin.member.repository.MemberRepository
import org.tenten.bittakotlin.profile.entity.Profile
import org.tenten.bittakotlin.profile.service.ProfileService
import org.tenten.bittakotlin.security.dto.TokenRequestDto
import org.tenten.bittakotlin.security.service.TokenService
import org.tenten.bittakotlin.security.util.JwtTokenUtil

@Service
@RequiredArgsConstructor
@Slf4j
class MemberServiceImpl (
private val memberRepository: MemberRepository,
private val bCryptPasswordEncoder: BCryptPasswordEncoder,
private val profileService: ProfileService

private val profileService: ProfileService,
private val tokenService: TokenService
): MemberService {
override fun login(requestDto: MemberRequestDTO.Login): MemberResponseDTO.Login {
val member = memberRepository.findByUsername(requestDto.username)
?: throw MemberException.BAD_CREDENTIAL.get()

if (!bCryptPasswordEncoder.matches(requestDto.password, member.password)) {
throw MemberException.BAD_CREDENTIAL.get()
}

val tokenResponseDto = tokenService.create(TokenRequestDto.Create(
username = member.username,
role = member.role!!
))

val profile: Profile = profileService.getByUsername(member.username)

return MemberResponseDTO.Login(
accessToken = tokenResponseDto.accessToken,
refreshToken = tokenResponseDto.refreshToken,
profileId = profile.id!!,
profileUrl = profile.profileUrl!!
)
}

override fun join(joinDTO: MemberRequestDTO.Join) {
val username = joinDTO.username
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ interface ProfileService {

fun getByPrincipal(): Profile

fun getByUsername(username: String): Profile

fun updateProfileImage(requestDto: MediaRequestDto.Upload): String

fun deleteProfileImage()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@ class ProfileServiceImpl(
.orElseThrow { NoSuchElementException() }
}

override fun getByUsername(username: String): Profile {
return profileRepository.findByUsername(username)
.orElseThrow { NoSuchElementException() }
}

companion object {
private val logger: Logger = LoggerFactory.getLogger(ProfileServiceImpl::class.java)
}
Expand Down
Loading

0 comments on commit 508e99a

Please sign in to comment.