사용자가 로그인시도를 할 때 요청 본문의 데이터를 한 줄씩 읽어 출력해 봤습니다.
각 다른식으로 출력되는 것을 확인할 수 있었습니다.
클라이언트로부터 전송된 데이터를 적절하게 처리하고 분석하기 위해 파싱을 사용해 인증을 수행해야합니다.
파싱을 사용하는 이유는 클라이언트로부터 전송된 데이터 요청에 필요한 인증정보를 추출하고 이를 사용하여 인증을 수행하기 위함입니다.
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을 비활성화해서 직접 만들어야합니다. )
코드를 순서대로 설명하자면 아래와 같습니다.
attemptAuthentication 사용자 인증이 완료되면, successfulAuthentication 메서드가 실행됩니다.
정상적으로 메서드가 동작하는지 테스트하기위해 print문으로 출력해보겠습니다.