관리 메뉴

bright jazz music

blog 35 : JWT를 이용한 인증 - 만들어보자 본문

Projects/blog

blog 35 : JWT를 이용한 인증 - 만들어보자

bright jazz music 2023. 2. 19. 22:28

1. 사용할 JWT 라이브러리 선택

 

JWT.IO

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

jwt.io

https://github.com/jwtk/jjwt

 

GitHub - jwtk/jjwt: Java JWT: JSON Web Token for Java and Android

Java JWT: JSON Web Token for Java and Android. Contribute to jwtk/jjwt development by creating an account on GitHub.

github.com

가장 사용자가 많은 라이브러리를 사용한다.

 

 

2. build.gradle에 의존성 주입

//build.gradle
//jwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'

gradle sync를 마치면 설치가 완료된 것이다.

2. 사용

jws 는 JWT signature이다. 최종 완성된 json 스트링이라고 봐도 된다.

 

//AuthController.java

package com.endofma.blog.controller;

import com.endofma.blog.request.Login;
import com.endofma.blog.response.SessionResponse;
import com.endofma.blog.service.AuthService;
import io.jsonwebtoken.Jwts;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.ResponseCookie;
//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.RestController;

//jwt
import java.security.Key;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.SignatureAlgorithm;


import java.time.Duration;
import java.util.Base64;


@Slf4j
@RestController
@RequiredArgsConstructor
public class AuthController {

    //생성자를 통한 주입
    //private final UserRepository userRepository;
    //로그인 및 인증 절차를 서비스에 위임
    private final AuthService authService;

//AuthController.java
    @PostMapping("/auth/login")
//    public ResponseEntity<Object> login(@RequestBody Login login){
    public SessionResponse login(@RequestBody Login login){

        String accessToken = authService.signin(login);

//        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256); 이렇게 하면 요청이 올 때마다 key 값이 다르게 저장된다. 따라서 일반적으로는 고정하여 사용한다.
        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        byte [] encodedKey  = key.getEncoded();
        String strKey = Base64.getEncoder().encodeToString(encodedKey);

        String jws = Jwts.builder().setSubject("Joe").signWith(key).compact();

        return new SessionResponse(jws);

    }
}

 

auth.http

POST http://localhost:8080/auth/login

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 20 Feb 2023 13:05:14 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
  "accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.wl9wC-M2XhboVIM06CoVhAy7Bafh71rA5kPT9laUPqQ"
}
Response file saved.
> 2023-02-20T220514.200.json

Response code: 200; Time: 555ms (555 ms); Content length: 101 bytes (101 B)

Cookies are preserved between requests:
> D:\personal\blog\.idea\httpRequests\http-client.cookies

토큰을 반환해 주는 것을 확인할 수 있다.

 

3. 값 들어가는지 확인해보기

//AuthController.java

package com.endofma.blog.controller;

import com.endofma.blog.request.Login;
import com.endofma.blog.response.SessionResponse;
import com.endofma.blog.service.AuthService;
import io.jsonwebtoken.Jwts;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.ResponseCookie;
//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.RestController;

//jwt
import java.security.Key;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.SignatureAlgorithm;


import java.time.Duration;
import java.util.Base64;


@Slf4j
@RestController
@RequiredArgsConstructor
public class AuthController {

    //생성자를 통한 주입
    //private final UserRepository userRepository;
    //로그인 및 인증 절차를 서비스에 위임
    private final AuthService authService;

//AuthController.java
    @PostMapping("/auth/login")
//    public ResponseEntity<Object> login(@RequestBody Login login){
    public SessionResponse login(@RequestBody Login login){

        String accessToken = authService.signin(login);

//        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256); 이렇게 하면 요청이 올 때마다 key 값이 다르게 저장된다. 따라서 일반적으로는 고정하여 사용한다.
        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        byte [] encodedKey  = key.getEncoded();
        String strKey = Base64.getEncoder().encodeToString(encodedKey);

        String jws = Jwts.builder().setSubject("Joe").signWith(key).compact();

        return new SessionResponse(jws);

    }
}

 

//AuthResolver.java

package com.endofma.blog.config;

import com.endofma.blog.config.data.UserSession;
import com.endofma.blog.domain.Session;
import com.endofma.blog.exception.Unauthorized;
import com.endofma.blog.repository.SessionRepository;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

@Slf4j
@RequiredArgsConstructor
public class AuthResolver implements HandlerMethodArgumentResolver {

    //주입
    private final SessionRepository sessionRepository;
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        //컨트롤러에서 사용할 어노테이션이나 DTO가 사용자가 사용하려는 것이 맞는지, 지원하는지 체크한다.
        return parameter.getParameterType().equals(UserSession.class); //UserSession 클래스를 사용하는 것이 맞는지 확인. 맞으면 컨트롤러에 값 할당
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        //실제로 해당 DTO에 값을 세팅해준다.

        String jws = webRequest.getHeader("Authorization"); //헤더의 값으로 확인해준다.
        if (jws == null || jws.equals("")){
            throw new Unauthorized();
        }

        try {
            Jwts.parserBuilder()
                    .setSigningKey("C") //사인값 추가
                    .build()
                    .parseClaimsJws(jws);
            //OK, we can trust this JWT
        } catch (JwtException e) {
            throw new Unauthorized();
            //don't trust the JWT!
        }

        //db를 조회할 필요 없기 때문에 주석처리
//        Session session = sessionRepository.findByAccessToken(accessToken)
//                .orElseThrow(Unauthorized::new);
        return null;

    }
}

 

### auth.http

POST http://localhost:8080/auth/login
Content-Type: application/json

{
  "email" : "catnails@gmail.com",
  "password" : "1234"
}

 

 

4. 값 만들어서 인증하기

//AuthResolver.java

package com.endofma.blog.config;

import com.endofma.blog.config.data.UserSession;
import com.endofma.blog.domain.Session;
import com.endofma.blog.exception.Unauthorized;
import com.endofma.blog.repository.SessionRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

@Slf4j
@RequiredArgsConstructor
public class AuthResolver implements HandlerMethodArgumentResolver {

    //주입
    private final SessionRepository sessionRepository;
    private final String KEY = "Kz06PMZdP03FQVS3m8Jg9gKSEQjV4/NePMOq1F0GNH4=";

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        //컨트롤러에서 사용할 어노테이션이나 DTO가 사용자가 사용하려는 것이 맞는지, 지원하는지 체크한다.
        return parameter.getParameterType().equals(UserSession.class); //UserSession 클래스를 사용하는 것이 맞는지 확인. 맞으면 컨트롤러에 값 할당
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        //실제로 해당 DTO에 값을 세팅해준다.

        String jws = webRequest.getHeader("Authorization"); //헤더의 값으로 확인해준다.
        if (jws == null || jws.equals("")){
            throw new Unauthorized();
        }

        byte[] decodedKey = Base64.decodeBase64(KEY); //스트링 값이었던 것을 바이트 값으로 변환한다. setSigningKey(String)이 폐기되어서.

        try {
            Jws<Claims> claims = Jwts.parserBuilder()
//                    .setSigningKey(KEY) //사인값 추가 deprecated
                    .setSigningKey(decodedKey) //파라미터로 바이트 값이 들어간다.
                    .build()
                    .parseClaimsJws(jws);

            log.info(">>>>>{}", claims );
            //OK, we can trust this JWT
        } catch (JwtException e) {
            throw new Unauthorized();
            //don't trust the JWT!
        }


//        Cookie[] cookies = servletRequest.getCookies(); //배열로 받는다.

//        if (cookies.length == 0) {
//            log.error("쿠키가 없음");
//            throw new Unauthorized();
//        }

//        String accessToken = cookies[0].getValue();

        //db를 조회할 필요 없기 때문에 주석처리
//        Session session = sessionRepository.findByAccessToken(accessToken)
//                .orElseThrow(Unauthorized::new);

//        return new UserSession(1L);
//        return new UserSession(session.getUser().getId()); //컨트롤러로 넘겨준다.
        return null;

    }
}

 

//AuthController.java

package com.endofma.blog.controller;

import com.endofma.blog.request.Login;
import com.endofma.blog.response.SessionResponse;
import com.endofma.blog.service.AuthService;
import io.jsonwebtoken.Jwts;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.ResponseCookie;
//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.RestController;

//jwt
import java.security.Key;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.SignatureAlgorithm;


import javax.crypto.SecretKey;
import java.time.Duration;
import java.util.Base64;


@Slf4j
@RestController
@RequiredArgsConstructor
public class AuthController {

    //생성자를 통한 주입
    //private final UserRepository userRepository;
    //로그인 및 인증 절차를 서비스에 위임
    private static final String KEY = "Kz06PMZdP03FQVS3m8Jg9gKSEQjV4/NePMOq1F0GNH4=";
    private final AuthService authService;
    //앞으로 인증에 사용할 암호화 키. 유출되어서는 안 된다. 여기에는 테스트용으로 사용하기 위해 적어 놓는다.

//AuthController.java
    @PostMapping("/auth/login")
//    public ResponseEntity<Object> login(@RequestBody Login login){
    public SessionResponse login(@RequestBody Login login){

        String accessToken = authService.signin(login);

//        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256); 이렇게 하면 요청이 올 때마다 key 값이 다르게 저장된다. 따라서 일반적으로는 고정하여 사용한다.
//        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        SecretKey key = Keys.hmacShaKeyFor(Base64.getDecoder().decode(KEY));

        //        키 값을 복호화 하여 보기 위해 추가한 코드.
//        byte [] encodedKey  = key.getEncoded();
//        String strKey = Base64.getEncoder().encodeToString(encodedKey);
        //base64는 바이트를 스트링으로, 또는 그 반대로 변환한다.
//Kz06PMZdP03FQVS3m8Jg9gKSEQjV4/NePMOq1F0GNH4=
        String jws = Jwts.builder().setSubject("Joe").signWith(key).compact();

        return new SessionResponse(jws);

    }
}

 

 

5. 최종 수정

 

AuthController.java

//AuthController.java

package com.endofma.blog.controller;

import com.endofma.blog.request.Login;
import com.endofma.blog.response.SessionResponse;
import com.endofma.blog.service.AuthService;
import io.jsonwebtoken.Jwts;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.ResponseCookie;
//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.RestController;

//jwt
import java.security.Key;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.SignatureAlgorithm;


import javax.crypto.SecretKey;
import java.time.Duration;
import java.util.Base64;


@Slf4j
@RestController
@RequiredArgsConstructor
public class AuthController {

    //생성자를 통한 주입
    //private final UserRepository userRepository;
    //로그인 및 인증 절차를 서비스에 위임
    private static final String KEY = "Kz06PMZdP03FQVS3m8Jg9gKSEQjV4/NePMOq1F0GNH4=";
    private final AuthService authService;
    //앞으로 인증에 사용할 암호화 키. 유출되어서는 안 된다. 여기에는 테스트용으로 사용하기 위해 적어 놓는다.

//AuthController.java
    @PostMapping("/auth/login")
//    public ResponseEntity<Object> login(@RequestBody Login login){
    public SessionResponse login(@RequestBody Login login){

        Long userId = authService.signin(login);

//        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256); 이렇게 하면 요청이 올 때마다 key 값이 다르게 저장된다. 따라서 일반적으로는 고정하여 사용한다.
//        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        SecretKey key = Keys.hmacShaKeyFor(Base64.getDecoder().decode(KEY));

        //        키 값을 복호화 하여 보기 위해 추가한 코드.
//        byte [] encodedKey  = key.getEncoded();
//        String strKey = Base64.getEncoder().encodeToString(encodedKey);
        //base64는 바이트를 스트링으로, 또는 그 반대로 변환한다.
//Kz06PMZdP03FQVS3m8Jg9gKSEQjV4/NePMOq1F0GNH4=
        String jws = Jwts.builder().setSubject(String.valueOf(userId)).signWith(key).compact();

        return new SessionResponse(jws);

    }
}

 

AuthService.java

//AuthService.java

package com.endofma.blog.service;

import com.endofma.blog.domain.Session;
import com.endofma.blog.domain.User;
import com.endofma.blog.exception.InvalidSigninInformation;
import com.endofma.blog.repository.UserRepository;
import com.endofma.blog.request.Login;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

@Service
@RequiredArgsConstructor
public class AuthService {

    private final UserRepository userRepository;

    @Transactional
//    public String signin(Login login){
    public Long signin(Login login){
        User user = userRepository.findByEmailAndPassword(login.getEmail(), login.getPassword())
                .orElseThrow(InvalidSigninInformation::new);
        //세션 발급
        Session session = user.addSession();
//        return session.getAccessToken();

        return user.getId();
    }
}

 

AuthResolver.java

//AuthResolver.java

package com.endofma.blog.config;

import com.endofma.blog.config.data.UserSession;
import com.endofma.blog.domain.Session;
import com.endofma.blog.exception.Unauthorized;
import com.endofma.blog.repository.SessionRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

@Slf4j
@RequiredArgsConstructor
public class AuthResolver implements HandlerMethodArgumentResolver {

    //주입
    private final SessionRepository sessionRepository;
    private final String KEY = "Kz06PMZdP03FQVS3m8Jg9gKSEQjV4/NePMOq1F0GNH4=";

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        //컨트롤러에서 사용할 어노테이션이나 DTO가 사용자가 사용하려는 것이 맞는지, 지원하는지 체크한다.
        return parameter.getParameterType().equals(UserSession.class); //UserSession 클래스를 사용하는 것이 맞는지 확인. 맞으면 컨트롤러에 값 할당
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        //실제로 해당 DTO에 값을 세팅해준다.

        String jws = webRequest.getHeader("Authorization"); //헤더의 값으로 확인해준다.
        if (jws == null || jws.equals("")){
            throw new Unauthorized();
        }

        byte[] decodedKey = Base64.decodeBase64(KEY); //스트링 값이었던 것을 바이트 값으로 변환한다. setSigningKey(String)이 폐기되어서.

        try {
            Jws<Claims> claims = Jwts.parserBuilder()
//                    .setSigningKey(KEY) //사인값 추가 deprecated
                    .setSigningKey(decodedKey) //파라미터로 바이트 값이 들어간다.
                    .build()
                    .parseClaimsJws(jws);

            String userId = claims.getBody().getSubject();
            return new UserSession(Long.parseLong(userId));

            //OK, we can trust this JWT
        } catch (JwtException e) {
            throw new Unauthorized();
            //don't trust the JWT!
        }


//        Cookie[] cookies = servletRequest.getCookies(); //배열로 받는다.

//        if (cookies.length == 0) {
//            log.error("쿠키가 없음");
//            throw new Unauthorized();
//        }

//        String accessToken = cookies[0].getValue();

        //db를 조회할 필요 없기 때문에 주석처리
//        Session session = sessionRepository.findByAccessToken(accessToken)
//                .orElseThrow(Unauthorized::new);

//        return new UserSession(1L);
//        return new UserSession(session.getUser().getId()); //컨트롤러로 넘겨준다.


    }
}

 

PostController.java

//PostController.java

package com.endofma.blog.controller;

import com.endofma.blog.config.data.UserSession;
import com.endofma.blog.domain.Post;
import com.endofma.blog.exception.InvalidRequest;
import com.endofma.blog.request.PostCreate;
import com.endofma.blog.request.PostEdit;
import com.endofma.blog.request.PostSearch;
import com.endofma.blog.response.PostResponse;
import com.endofma.blog.service.PostService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Slf4j
@RestController
@RequiredArgsConstructor
public class PostController {
    //에러는 ExceptionController에서 처리한다.
    private final PostService postService;

    //postController.java
    @GetMapping("/foo")
    public Long foo(UserSession userSession){
        log.info(">>> {}", userSession.id);
        return userSession.id;
    }

    @GetMapping("/bar")
    public String bar(UserSession userSession){
        log.info(">>> {}", userSession.id);
        return "인증이 필요한 페이지";
    }



//PostController.java
    @PostMapping("/posts")
    public void post(@RequestBody @Valid PostCreate request) {
        //인증 방법
        //1. GET Parameter : @RequestParam String authorization
        //2. POST(body) value : 사용하지 않을 예쩡. PostCreate에 인증 코드를 추가해야 해서 설계가 무너진다. private String authrozation 같은.
        //3. Header로 받는 방법 : @RequestHeader String authorization

        //PostController의 post()에 보내는 요청의 제목에 "바보"라는 글자를 넣을 수 없다면.
//        if(request.getTitle().contains("바보")){
//            throw new InvalidRequest();
//        } 이렇게 데이터를 꺼내서 분리해서 재조립하는 방식보다는 아래처럼 메시지를 통해 가져오는 방식 권장

        request.validate(); //검증
        postService.write(request);
//        return Map.of();
    }

    //단건 조회
    @GetMapping("/posts/{postId}")
    public PostResponse get(@PathVariable Long postId){

        PostResponse response = postService.get(postId);
        return response;
    }

    //여러 글 조회(글 목록 가져오기)
    //  /posts
    @GetMapping("/posts")

    //글이 너무 많은 경우 비용이 너무 많이 든다.
    //DB가 뻗을 수 있음.
    //DB -> 애플리케이션 서버로 전달하는 시간, 트래픽 비용이 많이 발생할 수 있다.
    //따라서 페이지 설정

//    원래는 int로 받았음
//   public List<PostResponse> getList(@RequestParam int page){

// 그러나 사용의 용이성을 위해 pageable을 사용함
//   public List<PostResponse> getList(@PageableDefault Pageable pageable){ //1로 넘겨도 0으로 보정해서 넣어줌.
    //근데 PageableDefault의 기본 size가 10이라 yml에서 설정해도 먹히지 않는다.
    //이 떄는 어노테이션을 그대로 유지하면서 size를 파라미터로 넣어주는 방법이 있다.
    //public List<PostResponse> getList(@PageableDefault(size=10) Pageable pageable){

    //또는 어노테이션을 빼고 application.yml에서 default-page-size를 설정하여 해결할 수 수있다.

    //전에는 Pageable을 사용했으나 여러 요구사항을 수용 할 수 있는 클래스를 사용하기 위해
    //postSearch 클래스 사용


   public List<PostResponse> getList(@ModelAttribute PostSearch postSearch){//따로 만든 요청클래스 사용하려고 함
//   public List<PostResponse> getList(Pageable pageable){
        return postService.getList(postSearch);

    }

    @PatchMapping("/posts/{postId}")
    public void edit(@PathVariable Long postId, @RequestBody @Valid PostEdit request){


        postService.edit(postId, request);
    }

    @DeleteMapping("/posts/{postId}")
    public void delete(@PathVariable Long postId){
        postService.delete(postId);
        System.out.println("hello world2");

        System.out.println("test for test branch1");
    }

}

 

 

먼저 토큰 얻기

### auth.http

POST http://localhost:8080/auth/login
Content-Type: application/json

{
  "email" : "catnails@gmail.com",
  "password" : "1234"
}

 

로그인하여 토큰 획득

토큰 값:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.MFZVLmx0p7Y-P16K7gXRVQaaC3ghTpCqaivUoBEX0vM

 

###post.http
### 주석 #3개

GET http://localhost:8080/foo
Content-Type: application/json
Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.MFZVLmx0p7Y-P16K7gXRVQaaC3ghTpCqaivUoBEX0vM

토큰 값 사용하여 /foo api 접근

 

정상적으로 userId값 반환

Comments