[TIL] Today I Lerned - 230113

2023. 1. 14. 01:09기록/TIL

[TIL] Today I Lerned - 230113

 

230113 기록

 

프로젝트

 

  • 리프레시 토큰
  • 길고도 긴 리프레시 토큰을 구현 및 확인까지 끝냈다.
  • 토큰을 구현하는데 다른 동료분들에게 여쭤보고 이해하는 식으로 계속 진행을 했다.
  • 처음 구상
    • 액세스토큰으로 나눠진 부분에서 exception을 터트리면 자동으로 리프레시 토큰이 작동이 되도록 하는 것이 목적
    • 동료분들과 이야기를 하면서 해당 메서드 및 기능을 분리하는 것이 좋다고 생각하여 구상을 변경해서 접근했다.
  • 구상
    • 상황 : 기존의 AT(Access Token)이 exception - 기간만료를 터트리면 프런트 부분에서 RT(Refresh Token) 요청을 할 것이라 생각
    • /rest URI의 POST 요청이 들어오면 해당 메서드 실행
    • 메서드는 해당 RT가 유효한지 검사를 하고 해당 RT가 유효하면 AT를 반환한다.
    • 기존에 만들어진 메서드들을 이용하거나 조금씩 수정을 해서 해당 과정을 만들어냈다.
@PostMapping("/refresh")
public ResponseEntity shotRefreshToken(HttpServletRequest request,HttpServletResponse response) {
    return ResponseEntity.status(HttpStatus.OK).body(userService.getAccessToken(request,response));
}
public String getAccessToken(HttpServletRequest request, HttpServletResponse response) throws IllegalArgumentException {
    if(jwtUtil.checkRefreshToken(request)) {
        String username = filter.checkUser(request);
        User user = userRepository.findByUsername(username).orElseThrow(() -> new IllegalArgumentException("존재하지않는 유저입니다"));
        response.addHeader(JwtUtil.AUTHORIZATION_HEADER, jwtUtil.createToken(user.getUsername(), user.getUserRoleEnum()));
        return "Access 토큰이 재생성 되었습니다.";
    }
    throw new IllegalArgumentException("해당 토큰은 기한이 지난 토큰입니다");
}
// 해당 refresh 토큰이 유효한지 검사
public boolean checkRefreshToken(HttpServletRequest request) {
    String token = resolveRefreshToken(request);
    Claims claims ;
    if (token != null) {
        if (validateToken(token)) {
            return true;
            }else{
                return false;
            }
        }
        else {
            throw new IllegalArgumentException("Token Error");
        }
    }

// REFRESH_HEADER로 지정이 된 토큰을 풀어서 확인
public String resolveRefreshToken(HttpServletRequest request) {
    String bearerToken = request.getHeader(REFRESH_HEADER);   //Authorization bearer 띄고 Token == 토큰으로 나 자신을 인증하겠다
    if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) {
        return bearerToken.substring(7);
    }
    return null;
}
    
// 토큰에 오류가 있는지 없는지 확인    
public boolean validateToken(String token) {
    try {
        Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
        return true;
    } catch (SecurityException | MalformedJwtException e) {
        log.info("Invalid JWT signature, 유효하지 않는 JWT 서명 입니다.");
    } catch (ExpiredJwtException e) {
        log.info("Expired JWT token, 만료된 JWT token 입니다.");
    } catch (UnsupportedJwtException e) {
        log.info("Unsupported JWT token, 지원되지 않는 JWT 토큰 입니다.");
    } catch (IllegalArgumentException e) {
        log.info("JWT claims is empty, 잘못된 JWT 토큰 입니다.");
    }
    return false;
}

Spring rest docs 적용

 

테스트 코드의 발걸음을 시작했다. 그렇기에 테스트 코드로 문서를 자동화 시켜주는 Spring rest docs를 사용하려고 한다.

 

참고를 한 문서들은 아래 출처로 남겨놨다.

 

  • Rest Docs 사용 이유
    • 코드를 작성하고 리팩토링을 하다보면 기존의 설계한 틀에서 벗어나는 경우가 존재한다.
    • 해당 경우에 직접 api 명세서를 업데이트할 수도 있지만 사람이 놓치는 부분을 자동으로 해준다면 더 코드 작성에 시간을 들일 수 있다는 생각을 하게 되었고 해당 기능을 꼭 적용시켜보고 싶었다.
    • Spring Rest Docs의 경우 테스트코드가 작성이 된 컨트롤러 테스트 코드를 자동으로 문서화를 시켜준다.
    • 테스트 코드를 문서화 시키기에 기능이 돌아가는지 오류가 나는지 확인을 하여 검증이 된 부분만 문서화를 시킬 수 있다는 장점이 있다.
    • 또한 추후에 TDD를 통해 작업을 하게 된다면 메서드를 생성하면서 자동으로 문서로도 남긴다는 점에서 시간적 이점을 가져온다고 생각한다.

현재 Rest Docs html이 보이지 않는 상태여서 계속 고치면서 진행할 예정이다.

 


230114 추가

 

  • 코드를 작성하는 것까진 조금은 적응을 했지만 build.gradle 같은 환경설정의 부분은 공부가 미숙하다 보니 오류를 잡거나 찾기가 힘들었다.
    • 코드를 작성하는 것 뿐만 아니라 환경 설정 부분도 공부가 필요하다는 것을 느낌
  • 기존에 진행했던 과정을 하나씩 뜯어보며 각각의 코드들이 어떤 역할을 하는지, 어떤 작업을 서로 주고받는지 확인을 하면서 구조 파악하기

 

현재까지 등장했던 사항들

  • 기존 우아한형제들이 진행했던 gradle의 버전( 6 → 7 ) 이 달라서 참고하던 도중 방향을 잃고 작동 X
    • Gradle 버전에 맞춰서 build.gradle에 추가로 설정
    • org.asciidoctor.convert → asciidoctor.jvm.convert를 사용
      • adoc 파일을 변환하여 build에 저장하기 위해 사용

해당 파일들의 경로들을 설정해주는 역할을 한다.  후에 빌드를 하면 해당 디렉터리에 adoc 파일들이 생성이 된다.

 

이때 ext의 경우 gradle에서 변수를 사용하는 방법이며 해당 영역에서 사용된 변수는 전역변수로 취급하여 사용이 된다.

ext {
    snippetsDir = file('build/generated-snippets')
}

 

 

asciidoctor 설정부분이다.

  • 테스트가 실행되고 난 뒤에 실행
  • 아까 지정한 snippetDir로 파일 지정
  • configuration에서 선언한 asciidoctorExtension을 사용한다는 의미
asciidoctor {
    inputs.dir snippetsDir
    configurations 'asciidoctorExtensions' // 이부분!
    dependsOn test
}

 

dependsOn의 키워드는 해당 작업은 dependsOn뒤에 있는 작업이 실행된 뒤에 실행한다는 의미이다.

ext {
    snippetsDir = file('build/generated-snippets')
}

test {
    outputs.dir snippetsDir
    useJUnitPlatform()
//    finalizedBy 'asciidoctor'
}

asciidoctor {
    inputs.dir snippetsDir
    configurations 'asciidoctorExtensions' // 이부분!
    dependsOn test
}
asciidoctor.doFirst {
    delete file('src/main/resources/static/docs')
}

bootJar {
    dependsOn asciidoctor
    copy {
        from "${asciidoctor.outputDir}"
        into 'src/main/resources/static/docs'
    }
}

task copyDocument(type: Copy) {
    dependsOn asciidoctor
    from file("build/docs/asciidoc")
    into file("src/main/resources/static/docs")
}

build {
    dependsOn copyDocument
}

따라서 Test - asciidoctor - bootJar /  copyDocument - build의 방식으로 진행이 된다.

 


230115 추가

 

Test를 진행하면 build 폴더에 generated-snippets라는 폴더에 통과한 테스트 결괏값에 맞춰서 각각의 adoc 문서가 생성

 

 

 

해당 문서들은 우리가 src 경로에서 docs /  asciidoc / {사용자 지정이름}. adoc 문서 생성을 하고 난 뒤 해당 문서에 넣을 수 있다.

 

// 예시
ifndef::snippets[]
:snippets: ./build/generated-snippets
endif::[]

== REQUEST

include::{snippets}/userController/http-request.adoc[]

== RESPONSE

include::{snippets}/userController/http-response.adoc[]

== REQUEST

include::{snippets}/userController/http-request.adoc[]

== RESPONSE

include::{snippets}/userController/http-response.adoc[]

 

include::라는 항목에 우리가 test를 통해 생성한  문서를 연결해 주면 자동으로 API가 보이게 된다.

 

 

그리고 플러그인에서 AsciiDoc을 설치하면 해당 작성된 문서를 미리 볼 수 있다.

 

 

해당 문서는 http://localhost:8080/docs/{사용자 지정}. html으로 들어가면 확인이 가능하다.

 

 

 

spring rest docs의 적용을 드디어 해보고 결실을 맺을 수 있었다. 비록 처음 적용해 보는 것이라 테스트 코드 작성부터 Build.gradle을 통해 환경을 설정해 보고 이해를 하는 등의 여러 가지를 같이 키워드로 얻고 공부를 하는 시간을 갖느라 시간이 계획보다 오래 걸렸다. 그래도 적용을 해보면서 어떤 과정이 필요한지 알았으니 이제 다른 테스트들도 작성하여 해당 api명세서를 만들어보려고 한다.

 

 

출처

 

Spring Rest Docs 적용 | 우아한 형제들 기술블로그 (woowahan.com)

 

Spring Rest Docs 적용 | 우아한형제들 기술블로그

{{item.name}} 안녕하세요? 우아한형제들에서 정산시스템을 개발하고 있는 이호진입니다. 지금부터 정산시스템 API 문서를 wiki 에서 Spring Rest Docs 로 전환한 이야기를 해보려고 합니다. 1. 전환하는

techblog.woowahan.com

API 문서 자동화 - Spring REST Docs 팔아보겠습니다 (techcourse.co.kr)

 

API 문서 자동화 - Spring REST Docs 팔아보겠습니다

프로덕션 코드와 분리하여 문서 자동화를 하고 싶다고요? 신뢰도 높은 API 문서를 만들고 싶다고요? 테스트가 성공해야 문서를 만들 수 있다!! Spring REST Docs가 있습니다. API 문서를 자동화 도구로

tecoble.techcourse.co.kr

Spring REST Docs

 

Spring REST Docs

It helps you to produce documentation that is accurate, concise, and well-structured. This documentation then allows your users to get the information they need with a minimum of fuss.

spring.io

Spring REST Docs 적용 및 최적화하기 | Backtony

 

Spring REST Docs 적용 및 최적화 하기

Java, JPA, Spring을 주로 다루고 공유합니다.

backtony.github.io

[Spring] Spring rest docs 적용기(gradle 7.0.2) (velog.io)

 

[Spring] Spring rest docs 적용기(gradle 7.0.2)

gradle 7 버전에서 spring rest docs 적용 방법과 겪은 문제

velog.io

 

[SPRING] Asciidoctor 빌드 오류(asGemPath()) | 나의 공부방 (jinseobbae.github.io)

 

[SPRING] Asciidoctor 빌드 오류(asGemPath())

오류

jinseobbae.github.io

 

'기록 > TIL' 카테고리의 다른 글

[TIL] Today I Lerned - 230117  (0) 2023.01.17
[TIL] Today I Lerned - 230116  (0) 2023.01.16
[TIL] Today I Lerned - 230112  (0) 2023.01.12
[TIL] Today I Lerned - 230111  (0) 2023.01.11
[TIL] Today I Lerned - 230110  (0) 2023.01.10