-
Notifications
You must be signed in to change notification settings - Fork 0
#15,16 - Security 설정, 회원가입 개발 #34
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
Changes from 31 commits
eaef785
e52037e
fa58236
8ee5950
bf66b7c
3bff1a2
da78e47
6846bd5
92f29c8
66f6489
1bc7c8e
412af65
6efb850
8f61085
8cd802b
9c8c9ac
35659a6
e8056ed
e17f041
adab3e5
bb46e8d
30c01b2
dbc670f
b8f61d4
d71ec8b
1de8e82
c4b4000
810f5af
2acf2bd
aa52eac
6d73bee
991d491
652bf3f
8f9dc12
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
[submodule "app/src/main/resources/backend-submodule"] | ||
path = app/src/main/resources/backend-submodule | ||
url = https://github.com/yapp-wespot/backend-submodule.git | ||
[submodule "app/src/main/resources/config"] | ||
path = app/src/main/resources/config | ||
url = https://github.com/yapp-wespot/config.git |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package com.wespot.auth | ||
|
||
import com.wespot.auth.dto.request.AuthLoginRequest | ||
import com.wespot.auth.dto.request.RefreshTokenRequest | ||
import com.wespot.auth.dto.request.SignUpRequest | ||
import com.wespot.auth.dto.response.SignUpResponse | ||
import com.wespot.auth.dto.response.TokenResponse | ||
import com.wespot.auth.service.AuthService | ||
import org.springframework.http.HttpStatus | ||
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 | ||
|
||
@RestController | ||
@RequestMapping("/api/v1/auth") | ||
class AuthController( | ||
private val authService: AuthService | ||
) { | ||
|
||
@PostMapping("/login") | ||
fun signIn( | ||
@RequestBody request: AuthLoginRequest | ||
): Any { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 자기야 Function 내부에는 위, 아래 공백 안두어도 괜찮을 것 같아요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 위 아래 공백은, 지금 작업하시기에는 시간이 걸리니, 차차 제거해나가도록 하시죠! |
||
val response = authService.socialAccess(request) | ||
|
||
return if (response is SignUpResponse) { | ||
ResponseEntity.status(HttpStatus.ACCEPTED).body(response) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이거는 아직 사용자가 소셜로그인만 하고 회원가입을 안한 상태인가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 맞아요 이 이후에 회원가입 진행하게돼요! |
||
} else { | ||
ResponseEntity.ok() | ||
.body(response) | ||
} | ||
|
||
} | ||
|
||
@PostMapping("/signup") | ||
fun signUp( | ||
@RequestBody request: SignUpRequest | ||
): ResponseEntity<TokenResponse> { | ||
|
||
val signUp = authService.signUp(request) | ||
|
||
return ResponseEntity.ok() | ||
.body(signUp) | ||
|
||
} | ||
|
||
@PostMapping("/reissue") | ||
fun reissue( | ||
@RequestBody request: RefreshTokenRequest | ||
): ResponseEntity<TokenResponse> { | ||
|
||
val response = authService.reIssueToken(request) | ||
|
||
return ResponseEntity.ok() | ||
.body(response) | ||
|
||
} | ||
|
||
@PostMapping("/revoke") | ||
fun revoke(): ResponseEntity<Unit> { | ||
|
||
authService.revoke() | ||
|
||
return ResponseEntity.noContent().build() | ||
|
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package com.wespot.config.security | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import jakarta.servlet.FilterChain | ||
import jakarta.servlet.http.HttpServletRequest | ||
import jakarta.servlet.http.HttpServletResponse | ||
import org.springframework.http.HttpStatus | ||
import org.springframework.http.MediaType | ||
import org.springframework.http.ProblemDetail | ||
import org.springframework.stereotype.Component | ||
import org.springframework.util.AntPathMatcher | ||
import org.springframework.web.filter.OncePerRequestFilter | ||
import java.net.URI | ||
import kotlin.text.Charsets.UTF_8 | ||
|
||
@Component | ||
class CustomUrlFilter( | ||
private val objectMapper: ObjectMapper | ||
) : OncePerRequestFilter() { | ||
|
||
private val antPathMatcher = AntPathMatcher() | ||
|
||
private val validUrlPatterns = listOf( | ||
"/health", | ||
"/", | ||
"/api/v1/auth/reissue", | ||
"/api/v1/auth/login", | ||
"/api/v1/auth/signup", | ||
"/api/v1/auth/revoke", | ||
) | ||
Comment on lines
+23
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 앞으로 여기다가 url 추가하면 되겠네요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 맞아요 근데 이것도 조금 불편할 것 같기도 해서 개선해보는거 나중에 시도해볼게요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네네! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 뭔가 메타데이터 가져와서 하는 방법이 있을 것 같은데 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아니면 리플렉션으로도 가능할 것 같기도 하고오옹 |
||
|
||
override fun doFilterInternal( | ||
request: HttpServletRequest, | ||
response: HttpServletResponse, | ||
filterChain: FilterChain | ||
) { | ||
|
||
if (!isValidUrl(request)) { | ||
handleInvalidUrl(request, response) | ||
return | ||
} | ||
filterChain.doFilter(request, response) | ||
|
||
} | ||
|
||
private fun isValidUrl(request: HttpServletRequest): Boolean { | ||
|
||
val requestUri = request.requestURI | ||
|
||
return validUrlPatterns.any { antPathMatcher.match(it, requestUri) } | ||
|
||
} | ||
|
||
private fun handleInvalidUrl( | ||
request: HttpServletRequest, | ||
response: HttpServletResponse | ||
) { | ||
|
||
response.contentType = MediaType.APPLICATION_JSON_VALUE | ||
response.characterEncoding = UTF_8.name() | ||
response.status = HttpStatus.NOT_FOUND.value() | ||
|
||
val body = objectMapper.writeValueAsString( | ||
ProblemDetail.forStatusAndDetail( | ||
HttpStatus.NOT_FOUND, | ||
NoSuchFieldException("잘못된 URL입니다.").message!!, | ||
).apply { | ||
type = URI.create("/errors/not-found") | ||
instance = URI.create(request.requestURI) | ||
} | ||
) | ||
|
||
response.writer.write(body) | ||
|
||
} | ||
} | ||
Comment on lines
+54
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 키야 좋네요 👍 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.wespot.config.security | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import jakarta.servlet.http.HttpServletRequest | ||
import jakarta.servlet.http.HttpServletResponse | ||
import org.springframework.http.HttpStatus | ||
import org.springframework.http.MediaType | ||
import org.springframework.http.ProblemDetail | ||
import org.springframework.security.access.AccessDeniedException | ||
import org.springframework.security.web.access.AccessDeniedHandler | ||
import org.springframework.stereotype.Component | ||
import java.net.URI | ||
import kotlin.text.Charsets.UTF_8 | ||
|
||
@Component | ||
class JwtAccessDeniedHandler( | ||
private val objectMapper: ObjectMapper | ||
) : AccessDeniedHandler { | ||
override fun handle( | ||
request: HttpServletRequest, | ||
response: HttpServletResponse, | ||
exception: AccessDeniedException | ||
) { | ||
|
||
response.contentType = MediaType.APPLICATION_JSON_VALUE | ||
response.characterEncoding = UTF_8.name() | ||
response.status = HttpStatus.FORBIDDEN.value() | ||
|
||
val body = objectMapper.writeValueAsString( | ||
ProblemDetail.forStatusAndDetail( | ||
HttpStatus.UNAUTHORIZED, | ||
AccessDeniedException("자신의 것만 가능합니다").message!!, | ||
).apply { | ||
type = URI.create("/errors/forbidden") | ||
instance = URI.create(request.requestURI) | ||
} | ||
) | ||
response.writer.write(body) | ||
|
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package com.wespot.config.security | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import jakarta.servlet.http.HttpServletRequest | ||
import jakarta.servlet.http.HttpServletResponse | ||
import org.springframework.http.HttpStatus | ||
import org.springframework.http.MediaType | ||
import org.springframework.http.ProblemDetail | ||
import org.springframework.security.authentication.BadCredentialsException | ||
import org.springframework.security.core.AuthenticationException | ||
import org.springframework.security.web.AuthenticationEntryPoint | ||
import org.springframework.stereotype.Component | ||
import java.net.URI | ||
import kotlin.text.Charsets.UTF_8 | ||
|
||
@Component | ||
class JwtAuthenticationEntryPoint( | ||
private val objectMapper: ObjectMapper | ||
) : AuthenticationEntryPoint { | ||
override fun commence( | ||
request: HttpServletRequest, | ||
response: HttpServletResponse, | ||
authException: AuthenticationException? | ||
) { | ||
|
||
response.contentType = MediaType.APPLICATION_JSON_VALUE | ||
response.characterEncoding = UTF_8.name() | ||
response.status = HttpStatus.UNAUTHORIZED.value() | ||
|
||
val body = objectMapper.writeValueAsString( | ||
ProblemDetail.forStatusAndDetail( | ||
HttpStatus.UNAUTHORIZED, | ||
BadCredentialsException("").message!!, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 예외 메시지 추가해야할 것 같아요! |
||
).apply { | ||
type = URI.create("/errors/unauthenticated") | ||
instance = URI.create(request.requestURI) | ||
} | ||
) | ||
response.writer.write(body) | ||
|
||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.wespot.config.security | ||
|
||
import com.wespot.auth.JwtTokenInfo | ||
import com.wespot.auth.port.`in`.AuthenticationUseCase | ||
import jakarta.servlet.FilterChain | ||
import jakarta.servlet.http.HttpServletRequest | ||
import jakarta.servlet.http.HttpServletResponse | ||
import org.springframework.security.authentication.BadCredentialsException | ||
import org.springframework.security.core.context.SecurityContextHolder | ||
import org.springframework.stereotype.Component | ||
import org.springframework.util.StringUtils | ||
import org.springframework.web.filter.OncePerRequestFilter | ||
|
||
@Component | ||
class JwtAuthenticationFilter( | ||
private val authenticationUseCase: AuthenticationUseCase, | ||
private val jwtAuthenticationEntryPoint: JwtAuthenticationEntryPoint, | ||
) : OncePerRequestFilter() { | ||
|
||
override fun doFilterInternal( | ||
request: HttpServletRequest, | ||
response: HttpServletResponse, | ||
filterChain: FilterChain | ||
) { | ||
val token = extractToken(request) | ||
if (token != null && StringUtils.hasText(token)) { | ||
try { | ||
authenticateUserByToken(token) | ||
} catch (e: BadCredentialsException) { | ||
jwtAuthenticationEntryPoint.commence(request, response, authException = null) | ||
return | ||
} | ||
} | ||
filterChain.doFilter(request, response) | ||
} | ||
|
||
private fun authenticateUserByToken(token: String) { | ||
try { | ||
val authentication = authenticationUseCase.getAuthentication(token) | ||
SecurityContextHolder.getContext().authentication = authentication | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이게 컨텍스트에 넣는거군요 |
||
} catch (e: BadCredentialsException) { | ||
SecurityContextHolder.clearContext() | ||
} | ||
} | ||
|
||
private fun extractToken(request: HttpServletRequest): String? { | ||
val bearerToken = request.getHeader(JwtTokenInfo.AUTHORIZATION_HEADER) | ||
return if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(JwtTokenInfo.BEARER_TYPE)) { | ||
bearerToken.substring(JwtTokenInfo.BEARER_TYPE.length).trim() | ||
} else null | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
자기야 이거 api 그냥 넣을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 ㅋㅋ 저거 안뺐네요,, 편한대로?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
일단 빼시죵!