JWT - json 로그인 요청에 대한 파싱과 사용자 인증 테스트

최고요·2023년 5월 2일
2

JWT V1 

목록 보기
13/15
post-thumbnail

postman 로그인 테스트 - x-www-form-urlencoded 회원정보 send


사용자가 로그인시도를 할 때 요청 본문의 데이터를 한 줄씩 읽어 출력해 봤습니다.



postman 로그인 테스트 - json 회원정보 send



각 다른식으로 출력되는 것을 확인할 수 있었습니다.

클라이언트로부터 전송된 데이터를 적절하게 처리하고 분석하기 위해 파싱을 사용해 인증을 수행해야합니다.

파싱을 사용하는 이유는 클라이언트로부터 전송된 데이터 요청에 필요한 인증정보를 추출하고 이를 사용하여 인증을 수행하기 위함입니다.




json 으로 넘어온 값을 파싱하기

package com.choigoyo.config.JWT;

import com.choigoyo.config.auth.PrincipalDetails;
import com.choigoyo.entity.UserEntityJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RequiredArgsConstructor
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    /**
     * Spring Security 의 UsernamePasswordAuthenticationFilter 를 확장하여 사용하게되면
     * http://localhost:8081/login 주소로 userName,password 를 post 형식으로 전송하면
     * UsernamePasswordAuthenticationFilter 가 동작함 SecurityConFig 클래스에 form 로그인을 비활성화 시켜서 동작하지 않는 상태이나,
     * JwtAuthenticationFilter 를 다시 SecurityConFig 클래스에 등록해주면 동작하게됨
     */

    private final AuthenticationManager authenticationManager;


    // http://localhost:8081/login 요청이 들어오면 authenticationManager 통해서 로그인시도
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        System.out.println("JwtAuthenticationFilter : 로그인 시도중...");

        // 1 사용자의 userName, password 를 받는다
        try {
            // json 데이터를 파싱해줌
            ObjectMapper objectMapper = new ObjectMapper();
            UserEntityJWT userEntityJWT = objectMapper.readValue(request.getInputStream(), UserEntityJWT.class);
            // 유저에 정보가 잘 담겼는지 print 해보기
            System.out.println(userEntityJWT);
            // 토큰 생성(userName, password 를 담은)
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                    new UsernamePasswordAuthenticationToken(userEntityJWT.getUserName(),userEntityJWT.getPassword());
            // authenticationManager.authenticate() 인증 수행하기
            // 그리고 PrincipalDetailsService 의 loadByUsername() 함수가 실행됨
            Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
            System.out.println(request.getInputStream()); // request.getInputStream() 은 HttpServletRequest 객체로부터 입력 스트림을 가져오는 데 사용
            // 클라이언트 또는 다른 웹브라우저에서 서버로 전송된 데이터를 읽는데 사용할 수 있는 InputStream 객체
            // authenticate 객체가 session 영역에 저장됨
            PrincipalDetails principalDetails = (PrincipalDetails)authenticate.getPrincipal();
            System.out.println("==================로그인 완료=================="); // 구분선
            System.out.println("principalDetails userName :"+principalDetails.getUsername());
            System.out.println("==============================================="); // 구분선
            return authenticate;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }
    
    // 순서 ->  attemptAuthentication 에서 인증이 정상적으로 실행되고 successfulAuthentication 메서드 실행
    // JWT 토큰을 만들어서 request 요청한 사용자에게 토큰을 응답과함께 전달
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        System.out.println("사용자 인증이 완료되어 successfulAuthentication 메서드가 실행됩니다.");
        super.successfulAuthentication(request, response, chain, authResult);
    }
    
}

객체에 잘 담겨 출력되었습니다.
이 값으로 로그인 시도를 하기위해 토큰을 만들어야합니다.
( formlogin을 비활성화해서 직접 만들어야합니다. )

코드를 순서대로 설명하자면 아래와 같습니다.

  1. ObjectMapper 객체를 생성합니다.
    ObjectMapper는 Jackson 라이브러리에서 제공하는 클래스로, JSON 데이터를 Java 객체로 변환하거나 Java 객체를 JSON으로 변환할 때 사용합니다.

  2. request.getInputStream()을 사용하여 UserEntityJWT 객체를 생성합니다.
    ObjectMapper의 readValue() 메소드를 사용하여 요청 본문의 JSON 데이터를 UserEntityJWT 클래스의 객체로 변환합니다. 이 작업을 통해 사용자가 제공한 userName과 password 정보가 userEntityJWT 객체에 저장됩니다.

  3. System.out.println(userEntityJWT)를 호출하여 변환된 userEntityJWT 객체의 내용을 출력합니다. 이를 통해 요청 본문의 데이터가 제대로 변환되었는지 확인할 수 있습니다.

  4. UsernamePasswordAuthenticationToken 객체를 생성합니다.
    UserEntityJWT 객체에서 userName과 password 정보를 가져와 UsernamePasswordAuthenticationToken 객체를 생성합니다. 이 토큰은 인증 프로세스에서 사용됩니다.

  5. authenticationManager.authenticate() 메소드를 호출하여 인증을 수행합니다.
    생성된 UsernamePasswordAuthenticationToken 객체를 사용하여 authenticationManager의 authenticate() 메소드를 호출합니다. 이 때 PrincipalDetailsService의 loadByUsername() 메소드가 실행되며, 인증이 성공적으로 수행되면 Authentication 객체를 반환합니다.

  6. request.getInputStream()을 출력합니다.
    마지막으로 System.out.println(request.getInputStream())를 호출하여 InputStream 객체를 출력합니다.


attemptAuthentication 사용자 인증이 완료되면, successfulAuthentication 메서드가 실행됩니다.

정상적으로 메서드가 동작하는지 테스트하기위해 print문으로 출력해보겠습니다.

profile
i'm best

0개의 댓글