Skip to content
This repository has been archived by the owner on Aug 13, 2022. It is now read-only.

스프링 시큐리티를 이용한 api 사용 인증 #68

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from

Conversation

kmmin78
Copy link
Collaborator

@kmmin78 kmmin78 commented Aug 1, 2021

주요 내용

  1. jws 검증 usecase를 추가한 테스트코드 작성
  2. jws 검증을 위한 filter 추가
  3. authenticationException handling을 위한 entrypoint 추가
  4. filter 및 entrypoint 설정에 추가

Closes #66

주요 내용

1. jws 검증 usecase를 추가한 테스트코드 작성
2. jws 검증을 위한 filter 추가
3. authenticationException handling을 위한 entrypoint 추가
4. filter 및 entrypoint 설정에 추가

Closes #66
@kmmin78 kmmin78 added the enhancement New feature or request label Aug 1, 2021
@kmmin78 kmmin78 requested review from FrancescoJo and neropsys August 1, 2021 07:19
@kmmin78 kmmin78 self-assigned this Aug 1, 2021
@FrancescoJo
Copy link
Collaborator

FrancescoJo commented Aug 4, 2021

음, 인증 추가 작업인데 @Preauthorize 가 보이질 않네요. 인증 과정이 어떻게 되는지 설명을 좀 해주실 수 있나요?

지금 구현하신 의도는 모든 API 기능은 인증 안하면 쓸 수 없는것인지... 궁금합니다.

https://docs.spring.io/spring-security/site/faq/faq.html

이 문서에서는 뭐라고 하나요?

ant matcher 와 @PreAuthorize 가 어떻게 다른지 설명해 주실 수 있나요?

@@ -19,7 +20,7 @@ import org.springframework.security.crypto.password.PasswordEncoder
class SecurityBeansDefinition {

@Bean
fun objectMapper() : ObjectMapper {
fun objectMapper(): ObjectMapper {
return jacksonObjectMapper()
Copy link
Collaborator

Choose a reason for hiding this comment

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

서버 실행할때 jackson-kotlin 어쩌고 경고 뜨진 않던가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

서버 시작을 아직 안해봤는데, 확인해보고 말씀드리겠습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

음.. 로컬에 wsl, docker, mysql 세팅하고 서버실행해봤는데, 말씀하신 경고는 뜨지 않고 있습니다.

import javax.servlet.http.HttpServletResponse

@Component
class UnauthorizedEntryPoint : AuthenticationEntryPoint {
Copy link
Collaborator

Choose a reason for hiding this comment

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

요거 네이밍 좋습니다.

/**
* 해당 키페어는 서버 시작할 때마다 재생성됩니다.
* 추후에는 미리 생성한 후 설정파일(ex : application-*.yml)에서 읽어들일 예정입니다.
*/
private val KEY_PAIR: KeyPair = Keys.keyPairFor(SignatureAlgorithm.RS256)
private const val BEARER_LENGTH: Int = 7
Copy link
Collaborator

Choose a reason for hiding this comment

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

7 은 무슨 의미인가요? Substring 의도로 만드신것 같은데 (Bearer )(<JSON_WEB_TOKEN>) 형식으로 정규표현식 선언한 다음, 뒤쪽 capturing group 을 take 하도록 구현하는게 좀더 가독성 높은 구현이 될 것 같습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

substring을 활용했는데, 아무래도 split을 활용하는게 더 간단할 것 같습니다.

@Test
fun `API 를 정상수행한다`() {
//정상적으로 로그인한 정보
val loginResponse = loginUserService.login(LoginRequest(email, password))
Copy link
Collaborator

Choose a reason for hiding this comment

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

통합 테스트에선 가급적이면 이런식으로 whitebox 에 의존한 구현보단 createUserAndLogin 같은 test helper function 을 만들고 그놈을 호출하는 식으로 구현하시는게 좀더 테스트 코드를 읽기 좋게 만들 수 있을 것 같습니다. (내부 구현도 LoginUserService 를 직접 호출하기보단 그냥 http call 하듯 구현한다면 좀더 blackbox testing 에 가깝게 구현할 수 있겠죠?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

안그래도 rest assured에서 http call을 한 후, 결과값을 가져오는 방법에 대해서 찾다가 잘 안찾아져서 일단 service로 바로 진행했었는데요.
말씀하신대로 hepler function을 이용해서 다시 한번 진행해보겠습니다.

@@ -190,8 +227,15 @@ class LoginWithSpringSecurityAndJwtTest {
inner class `유효하지 않으면` {

@Test
fun `403을 반환한다`() {

fun `401을 반환한다`() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

오류가 발생한다 (HTTP 403) 이 좀더 나을 것 같습니다.



@Component
class SpringApi {
Copy link
Collaborator

Choose a reason for hiding this comment

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

클래스 이름이... SpringApi 가 무슨 의미인지 잘 모르겠어요.
그리고 이놈 Test context 에서 로드하게 하려면 어떻게 구현해야 할까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

1.실험적인 코드를 작성한 터라 네이밍에 신경쓰지 못했습니다.

  1. @Inject, @Autowired 어노테이션으로 DI하면 될 것 같습니다.
    테스트 환경에서만 사용할 유틸성 클래스이기 때문에, 빈으로 생성 안하고 직접 생성하는 것도 방법이 될 수 있습니다.
    근데, 이 클래스는 인증이 필요한 api 리스트를 동적으로 생성해주고, 테스트 할 때 사용하려고 했는데, uri를 가져오는 건 별로 어렵지 않았으나, api마다 파라미터 정보를 가져오고, 데이터를 만들어주고 하는 것이 배보다 배꼽이 큰 느낌이라,
  • 해당 클래스는 실제로 사용하지 않았습니다. 앞으로의 수정에서 삭제될 예정입니다.

@kmmin78
Copy link
Collaborator Author

kmmin78 commented Aug 10, 2021

음, 인증 추가 작업인데 @Preauthorize 가 보이질 않네요. 인증 과정이 어떻게 되는지 설명을 좀 해주실 수 있나요?

지금 구현하신 의도는 모든 API 기능은 인증 안하면 쓸 수 없는것인지... 궁금합니다.

https://docs.spring.io/spring-security/site/faq/faq.html

이 문서에서는 뭐라고 하나요?

ant matcher 와 @PreAuthorize 가 어떻게 다른지 설명해 주실 수 있나요?

네, 현재 딱히 특정 url에 인증이 필요한지 결정된 것이 없기 때문에, 로그인 관련 api를 제외하고는 전부 인증이 필요하도록 설정했습니다.

해당 문서는 시큐리티 관련 faq로 보이네요. 읽어봤는데, 현재 말씀하신 부분 관련한 부분은 잘 모르겠습니다.

antmatcher는 configuration bean (WebSecurityConfigurerAdapter) 에서 해당 url path pattern과 일치하는 url 관련해서 설정할 수 있도록 합니다. hasRole 같은 권한 설정도 가능하구요.

@PreAuthorize 역시 컨트롤러의 메서드 마다 인증여부, 권한여부 등을 표현식으로 설정할 수 있는 걸로 알고 있습니다.

ant matcher는 설정파일에서 다루기 때문에 전역적으로 동작할 것이고, PreAuthorize는 메서드 별로 제어할 수 있다는 게 차이인 것 같습니다.

주요 내용

1. 테스트 함수 이름 변경
2. Bearer 추출 방식 변경에 따른 상수 제거 (substring -> split)
3. SpringApi 클래스 제거 (사용안함)

Closes #66
@kmmin78
Copy link
Collaborator Author

kmmin78 commented Aug 10, 2021

특이사항이 있습니다.
docker, mysql 세팅하고 application.yml까지 세팅완료하고 서버실행을 하는데는 문제가 없었습니다.

그런데, 테스트코드에서 이상하게 application.yml을 읽지 못하더군요.
최상위 프로젝트 (classpath:application.yml) 에 존재하는 걸 못읽는 것 같은데
app-main 모듈 내부에 application.yml을 복사해서 생성해주었더니 이건 잘 읽고 테스트 정상 수행되었습니다.

제가 원하는 건 default인 최상위 프로젝트의 application.yml을 읽었으면 하는 건데 따로 그거에 대한 설정을 찾기가 어렵네요.
검색되었던 문서는 대부분 test 환경의 application.yml과 로컬 환경의 application.yml을 분리하는 내용 뿐이었습니다.

@kmmin78
Copy link
Collaborator Author

kmmin78 commented Aug 10, 2021

테스트코드에서 black box test (http call) 하는 방식은 다음 커밋때 구현하겠습니다.

위에 application.yml 로드 하는 것 때문에 시간을 많이 날렸네요...

주요 내용

1. 메서드 보안방식 (@PreAuthorize) 반영 및 글로벌 filter 보안 제거
2. rest assured http call 방식을 이용한 테스트 및 헬퍼 클래스 작성

Closes #66
@kmmin78
Copy link
Collaborator Author

kmmin78 commented Aug 13, 2021

피드백 반영 완료했습니다.
내용은 다음과 같습니다.

  1. 메서드 보안방식 (@PreAuthorize) 반영 및 글로벌 filter 보안 제거
  2. rest assured http call 방식을 이용한 테스트 및 헬퍼 클래스 작성

Copy link
Collaborator

@FrancescoJo FrancescoJo left a comment

Choose a reason for hiding this comment

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

잘 봤습니다. 그리고 @neropsys 님도 WebSecurityConfig (이름은 마음대로 정하셔도 됨) 이렇게 구현하는구나- 라는것과, Spring Security 는 Servlet filter 단계에서 동작하는 거라는걸 확실하게 이해하고 넘어가시면 좋겠습니다.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

스프링 시큐리티를 이용한 api 사용 인증
3 participants