본문 바로가기

Backend

[SpringBoot] 게시판 만들기 (advanced type) (2) - JWT 적용하기 (Springboot 3.x, Swagger 3.0)

반응형

게시판에 적용시킬 JWT 기반 사용자 인증 방법  공부노트


  • 로그인 이후부터는 서버 입장에선 사용자가 누구인지 확인을 해야한다. 반드시! 과거에 활용된 방법 중 하나로 세션쿠키가 있지만, 외부의 공격에 취약한 단점도 있고, 구현하는게 그리 어렵지 않다. 지난 학기에 수행한 프로젝트에서 JWT를 이용한 사용자 인증 방식을 적용한 적이 있지만, 제대로 이해하지 못하고 클론코딩 하다시피 코드를 붙여넣어 적용시켰기 때문에 3-2학기를 끝내고 나니 머릿속이 백지상태가 되어버렸다. 이번 기회에 제대로 이해하고 코드를 작성해서 구현해볼 생각이다.  
  •  REST API를 최대한 활용해서 게시판을 구현하려고 하는 중이기도 하고, 웹 상에서 Form을 통해 로그인하는 것이 아니라 API 접근을 위해 클라이언트에게 토큰을 발급하는 과정을 생각했기 때문에, 적절한 인증 수단이라고 생각해서 이를 Spring Security와 함께 적용해보려 한다.

  • JWT는 json web token의 약자이고, 이름에서 묻어나듯 JSON 객체를 사용해서 토큰 자체에 정보를 저장하는 Web Token이다.  JWT의 최대 장점은 서버측 부하가 적어진다는 점이다. 서버는 비밀키만 알고있으면 되기 때문에 세션처럼 인증저장소가 따로 필요하지도 않다. 
  • https://jwt.io/    위의 사이트를 통해서 JWT를 더 공부할 수 있었다.

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

  • JWT는 Header, Payload, Signature로 구성되어있는데 중요한 것은 Signature부분이다. Header와 Payload는 base64로 인코딩 되어있어서 토큰을 갈취당한다면 두 내용은 쉽게 해독이 가능하여 외부로 노출이 된다. 하지만 Signature는 header와 payload를 기반으로 서버의 비밀키를 이용해 암호화되기 때문에 다른 사람이 해당 토큰을 갈취하여 payload에 본인의 정보를 넣는다고 한들 signature 내용이 유효하지 않아서 거부될 것이다.
  • 다만 단점이 있다면 토큰 자체를 탈취당해 제3자가 토큰이 본인 소유인 것처럼 서버로 전송해버리면 제3자가 접속에 성공할 수 있다는 것이다. 그래서 필요한 것이 리프레시토큰이다. 액세스토큰의 만료기간을 짧게 처리해두고 리프레시 토큰으로 사용자를 확인하는 것이다.  

이제 jwt를 적용시켜 게시판에 적용해보고자 한다.


SpringContextHolder 내부

다음 구조를 바탕으로 일단 클론코딩을 통해 코드를 구현해보고자 한다. 

 

일단 스프링 시큐리티는 인증 -> 인가 순서로 진행이 된다.

  • 1. 처음에 요청이 들어오면 AuthenticationFilter(UsernamePassAuthenticationFilter)부터 시작한다.
  • 2. 요청에 따른 UsernamePasswordAuthenticationToken을 생성한다. (Authentication 인터페이스의 구현체)
  • 3.  UsernamePasswordAuthenticationToken( =Token)을 AuthenticationManager에게 이 Token은 올바른 유저인지 물어본다.
  • 4. AuthenticationManager는 1개 이상의 AuthenticationProvider를 갖고 있는데, AuthenticationProvider 는 Token 객체를 적절히 판단하여 인증처리를 진행한다.
  • 5. AuthenticationManage 가 우리가 직접 커스텀한 서비스클래스(UserDetailsService 구현 클래스)에 해당 유저에게 인증요청을 보내 사용자 정보를 가져온다.
  • 6. UserDetailsService 구현 클래스는 사용자 정보를 가져와 UserDetails를 반환한다.
  • 7. Provider는 UserDetailsService에서 반환된 UserDetails와 클라이언트가 제공한 인증정보(Token)를 대조해서 이용자가 유효한 사용권한을 가지고 있는지 확인한 뒤 SecurityContext에 저장한다.

https://github.com/hyeon-gyu/NoticeBoard

 

GitHub - hyeon-gyu/NoticeBoard: 개인프로젝트 (게시판 구현)

개인프로젝트 (게시판 구현). Contribute to hyeon-gyu/NoticeBoard development by creating an account on GitHub.

github.com

 

현재 다기능 게시판을 구현 중이지만, security 관련 처리는 일단 마무리가 되었다. SecurityConfig class -> JwtAuthenticationFilter class 순으로 코드를 뜯어보며 JwtTokenUtil class와 CustomUserDetailsService class의메소드를 확인해보면 위의 그림들이 이해가 될 것이다.  


클론코딩을 통해서 하나하나 과정을 뜯어보던 중, UserDetailService에 대해서 주의깊게 알게 되었다. 

게시판을 처음 계획할 때, 사용자를 member가 아닌 user라는 이름으로 클래스를 만들었었는데, 이것이 큰 스노우볼을 일으킬 줄 상상도 못했다.  Spring Security에서 사용자의 정보를 담는 인터페이스로 UserDetail가 존재한다. 사용자의 정보를 불러오기 위해 해당 인터페이스로 메소드를 오버라이드하여 활용한다고 한다. 

이 그림에서 5번에 위치하는 UserDetailService가 사용자 정보를 불러오는 역할을 한다. 본 인터페이스에는 하나의 메소드가 존재하고 username 이라는 변수명을 이용해 사용자를 구분한다. 게시판 회원가입 당시 로그인아이디를 중복확인하는 절차를 거치고 회원가입이 진행되기 때문에 고유값을 가지는 loginId를 username에 담아서 활용하기로 했다. 

비밀번호 암호화 과정까지 적용하여 postman을 통한 몇가지 테스트를 진행해보았고 아래는 결과 사진이다. 

시큐리티 인증,인가 과정을 완벽하게 이해하고 구현을 한 것은 아니기 때문에 게시판을 완성한 후에, UserDetail부터 전반적인 과정에 대해서 다시 한번 과정을 분석해보고자 한다.

 


 

 


지금까진 아이디-닉네임 중복 검사, 회원가입, 로그인, JWT 구현까지 일단 테스트는 끝났다. 게시판 조회로 넘어가기 전 Swagger에 대해서 적용해보고자 한다. 프로젝트를 종료하는 시점에는 API명세를 정리하는 것이 내가 보기도, 남이 보기도 좋다고 생각한다. Notion을 통해서 일일이 번거롭게 만들고 보여주기식 정리는 내 성격상 시간을 쓰고 싶지 않는 느낌이 들기도 한다.

 

https://swagger.io/docs/specification/about/  

 

About Swagger Specification | Documentation | Swagger

What Is OpenAPI? OpenAPI Specification (formerly Swagger Specification) is an API description format for REST APIs. An OpenAPI file allows you to describe your entire API, including: Available endpoints (/users) and operations on each endpoint (GET /users,

swagger.io

공식 document를 참고하여 한번 공부해보았다. 

  • Swagger is a set of open-source tools built around the OpenAPI Specification that can help you design, build, document and consume REST APIs.
  • 의존성 추가와 조금의 코드 작성으로 간단하게 추가 가능하다는 장점이 있다.
  • 테스트를 진행할 수 있는 Test Page를 제공한다. 따라서 누구나 쉽게 테스트를 해 볼 수 있다. 

현재 사용중인 springboot version이 3.2.0 이라서 build.gradle에는 다음과 같이 작성했다.

implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'

다른 개발자분들의 적용 이슈 중에 하나가 springboot 2.x와 3.x의 라이브러리명이 달라서 발생하는 에러였다. 3.x는 위의 코드를 적용시키면 된다고 한다. 또한 JWT 적용 이슈가 하나 존재한다. 지금까지 구현한 부분들은 JWT인증 단계까지 거치지 않는 회원가입과 로그인이다보니 SwaggerConfig class를 작성할 때 별다른 조치 없이 진행하지만 나중을 대비하면 swagger가 jwt인증 절차를 잘 통과하게 세팅을 할 필요가 있다. 

 

@Configuration
@RequiredArgsConstructor
@OpenAPIDefinition(
        info = @Info(title = "다기능 게시판 서비스 API 명세서", description = "10일 안에 끝내는 개인 소규모 프로젝트 ", version = "advanced")
)
public class SwaggerConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
                .addSecurityItem(new SecurityRequirement().addList("bearerAuth"))
                .components(new Components()
                        .addSecuritySchemes("bearerAuth",
                                new SecurityScheme()
                                        .name("bearerAuth")
                                        .type(SecurityScheme.Type.HTTP)
                                        .scheme("bearer")
                                        .bearerFormat("JWT")));
    }
}

 

그리고 Swagger가 JWT 인증 절차를 받아야하는 URI가 있는 컨트롤러에는

@SecurityRequirement(name = "bearerAuth")

해당 어노테이션을 붙여주어서 진행하기로 한다.


참고 블로그

https://kimtaesoo99.tistory.com/118

 

Spring Security + JWT 회원가입, 로그인 기능 구현

인증(Authentication)과 권한(Authorization) 이 두 영역은 사실상 스프링 시큐리티의 핵심이다. 인증(Authentication): 보호된 리소스에 접근하는 대상, 즉 사용자에게 적절한 접근 권한이 있는지 확인하는

kimtaesoo99.tistory.com

https://velog.io/@yaho1024/Spring-Security-UserDetailsService-%EA%B5%AC%ED%98%84-%ED%95%B4%EB%B3%B4%EA%B8%B0

 

Spring Security - 4. UserDetailsService 구현 해보기

안녕하세요. INCHEOL'S 입니다. 저번시간에는 UsernamePasswordFilter와 그와 관련된 AuthenticationManager, AuthenticationProvider에 대해서 말씀드렸었는데 오늘은 그 중 AuthenticationProvider와

velog.io

 

반응형