TOKEN 구성
Header : alg: Signature 를 해싱하기 위한 알고리즘 정보를 갖고 있음
         typ: 토큰의 타입을 나타내는데 없어도 됨. 보통 JWT 를 사용
Payload : 서버와 클라이언트가 주고받는, 시스템에서 실제로 사용될 정보에 대한 내용을 담고 있음
          JWT 가 기본적으로 갖고 있는 키워드가 존재
          추가 가능
        iss: 토큰 발급자
        sub: 토큰 제목
        aud: 토큰 대상
        exp: 토큰의 만료시간
        nbf: Not Before
        iat: 토큰이 발급된 시간
        jti: JWT의 고유 식별자
Signature : 서버에서 토큰이 유효한지 검증하기 위한 문자열
          Header + Payload + Secret Key 로 값을 생성하므로 데이터 변조 여부를 판단 가능
          Secret Key 는 노출되지 않도록 서버에서 잘 관리 필요

절차
1. --> id/pwd 로그인 시도
2. <-- access token + refresh token 발급
3. --> API 요청시 access token을 헤더에 담아 요청
4. <-- API 응답 또는 Access token 만료 응답
5. --> 재발급 요청(Request Body에 Access token + refresh token)
6. <-- 토큰 검증후 새로운 Access Token + Refresh Token 발급

해당 모듈
JWT 관련 : TokenProvider: 유저 정보로 JWT 토큰을 생성 / 검증 / 토큰을 바탕으로 유저 정보 GET
          JwtFilter: Spring Request 앞단에 붙일 Custom Filter
Spring Security 관련 : JwtSecurityConfig: JWT Filter 등록
                      JwtAccessDeniedHandler: 접근 권한 없을 때 403 에러
                      JwtAuthenticationEntryPoint: 인증 정보 없을 때 401 에러
                      SecurityConfig: 스프링 시큐리티에 필요한 설정
                      SecurityUtil: SecurityContext 에서 전역으로 유저 정보를 제공하는 유틸 클래스

Spring security 비밀번호 검증
(Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);)

1. AuthService 에서 AuthenticationManagerBuilder 주입 받음
2. AuthenticationManagerBuilder 에서 AuthenticationManager 를 구현한 ProviderManager 생성
3. ProviderManager 는 AbstractUserDetailsAuthenticationProvider 의 자식 클래스인 DaoAuthenticationProvider 를 주입받아서 호출
4. DaoAuthenticationProvider 의 authenticate 에서는 retrieveUser 로 DB 에 있는 사용자 정보를 가져오고 additionalAuthenticationChecks 로 비밀번호 비교
5. retrieveUser 내부에서 UserDetailsService 인터페이스를 직접 구현한 CustomUserDetailsService 클래스의 오버라이드 메소드인 loadUserByUsername 가 호출됨

# Request
POST http://localhost:8080/api/auth/signup
Content-Type: application/json
{
  "email": "test@test.net",
  "password": "1q2w3e4r"
}

# Response
{
  "email": "test@test.net"
}
