/login 시
로그인 함수를 수행할
JwtAuthenticationFilter
클래스의
attemptAuthentication
메소드를 수정하면서
테스트해보자!
- JwtAuthenticationFilter.java
전체 코드는 맨 마지막에 올릴 예정
# 추가 부분

포스트맨 실행 결과

콘솔

잘 뜬다
위에 노란 박스가
저 스트림 바이트 안에 username과 password가 담겨져 있다는 것
더 자세하게 확인해보자
위 노란박스 부분을 아래 노란 박스 부분으로 수정한 다음
- JwtAuthenticationFilter.java

포스트맨으로 다시 로그인 시도!

콘솔 결과 ▼

포스트맨으로 보냈던 username과 password가 출력된 것을 볼 수 있다.
---
처 부분을 다시 parsing 해보자
여기서 유의할 점은 저 username과 password는 request.getParameter() 로 받을 수 없다.
--
포스트맨으로 로그인이 x-www-form-unrlencoded 로 id와 pw를 전송했었다.
json 타입으로 보낸다면 어떻게 될까?

콘솔 결과 ▼

위 스크린샷 처럼 json 타입으로 넘어오게 된다!
---
그럼 이제 내가 로그인 시도할 때 어떻게 하냐에 따라 달라질 것이라는 것을 알 수 있다!
일반적으로 web 클라이언트에서 로그인을 시도하면 x-www-formurlencoded 로 전송된다.
(안드로이드에서는 대부분 json, 자바스크립트도 json인 경우 많다)
--
넘어오는 값이
json 이라면 더 쉬운 방법으로

이 부분을 대체할 수 있다
한 번 해보자!! 기존에 작성한 거는 주석처리하고 하겠다!
아래처럼 수정했다.
ObjectMapper를 사용했다!
- JwtAuthenticationFilter.java

다시 포스트맨으로 username 과 password를 json으로 넘겨준 후 요청하면
콘솔창은 ▼

근데 여기서 실제로 로그인을 해보려면
토큰을 생성해주어야 한다 원래 폼로그인하면 자동으로 생성되는 건데
우리는 직접해야한다 지금은,,
- JwtAuthenticationFilter.java

이제 서버 재시작 후 postman으로 다시 로그인을 해보자!

(application.yml 의 jpa.hibernate.ddl-auto : create 때문에
기존에 회원가입 시켜놓은 계정이 사라졌다,,
update로 바꾸고 포스트맨을 통해 재가입을 진행하였다.


)

PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
System.out.println(principalDetails.getUsername());
구문으로 출력한 나의 로그인 정보 중 username 이 콘솔에 잘 출력된 것을 볼 수 있다!!
--
그 이후 단계에 jwt 토큰을 생성해서 로그인 request한 사용자에게 response로 jwt 토큰을 보내야 한다.
순서와 메소드 확인 부분이 너무 길어
수정 완료한 이번 게시물 최종 코드를 올려 놓겠다
- JwtAuthenticationFilter.java
package com.cos.jwt.jwt;
import com.cos.jwt.auth.PrincipalDetails;
import com.cos.jwt.model.User;
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.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
// 스프링 시큐리티에서 UsernamePasswordAuthenticationFilter 이 필터가 있는데
// 원래 이 필터는 /login 요청해서 username과 password를 전송하면(post)
// 이 필터가 동작한다.
// 근데 지금 동작하지 안했던 이유는
// spring security config에서 formLogin.disable() 해뒀기 때문
// 그렇다면 어떻게 하면 작동시킬 수 있을까?
// JwtAuthenticationFilter 이 필터를 사디
// SecruityConfig에 필터로 등록해주면 된다.
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
// 로그인을 진행하는 필터
private final AuthenticationManager authenticationManager;
// 로그인을 수행하는 함수
// login 요청을 하면 로그인 시도를 위해 실행되는 함수
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
System.out.println("JwtAuthenticationFilter:로그인 시도중");
//id, pw를 확인해서 db로 확인해서 이 id와 pw가 정상이면 ▼
// 1. username, password 를 받아서
try{
/*
// x-www-formurlencoded와 json 읽어와서 콘솔 찍어본 방법
BufferedReader br = request.getReader();
String input = null;
while ((input = br.readLine()) != null){
System.out.println(input);
*/
ObjectMapper om = new ObjectMapper(); // view로부터 넘어온 json을 파싱해주는 객체
User user = om.readValue(request.getInputStream(), User.class);
// ┗▶ 이렇게 하면 알아서 json 읽어온 값을 User 객체로 만들어준다.
System.out.println(user);
// 포스트맨으로 테스트하기 때문에 (폼로그인이 아니라서) 직접 임의 토큰 만들기
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()); // 첫번째 파마미터 username 두번째 파라미터 password
// 이렇게 임의로 만든 토큰으로 로그인 시도를 한 번 해보자!
// 토큰을 날리자 -> PrincipalDetailsService의 loadUserByUsername() 함수가 실행됨(username만 던짐 pw db에서 알아서 해줌 스프링이)
// PrincipalDetailsService의 loadUserByUsername()가 실행된 후 정상이면 authenctication이 리턴된다.
// 리턴되었다면 -> DB에 있는 username과 password가 일치한다는 뜻
// DB에 있는 username과 password가 일치한다.
Authentication authentication = // 내가 로그인한 정보가 담긴다.
authenticationManager.authenticate(authenticationToken);
// 제대로 로그인 되었다면 authentication 객체가 session 영역에 저장될 것이다! 그리고 꺼내봤을 때 null 이 아닐 것이다!
// 꺼내서 확인해보자! -> sysout로 확인해보자! username만 꺼내서 확인해보자!
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
System.out.println("로그인 완료됨" + principalDetails.getUsername()); // 값이 있다면 로그인 정상적으로 되었다는 뜻.
// authentication 객체가 session 영역에 정장을 해야하고 그 방법이 return 해주면 됨.
// 리턴의 이유는 권한 관리를 security 가 대신 해주기 때문에 편하려고 하는 거임.
// 굳이 JWT 토큰을 사용하면서 세션을 만들 이유가 없음. 근데 단지 권한 처리 때문에 session에 넣어줍니다.
// 넣기 직전에 해야 할 것이 있다 바로
// JWT 토큰 만들기 (이 과정을 여기 정의 말고 아래 정의 successfulAuthentication 메소드에서 수행됨.)
// 제대로 로그인이 되었다면 아래 값이 반환될 것이다.
// 이렇게 return 될 때 객체가 session에 저장된다.
return authentication;
}catch (Exception e){
e.printStackTrace();
}
// (-------------------------------------------------------------------------------------------------------
// 2. 정상인지 로그인 시도를 해본다. -> authenticationManager로 로그인 시도를 하면 PrincipalDetailsService가 호출된다.
// 그러면 PrincipalDetailseService에 있는 loadUserByUsername 메소드가 자동으로 실행된다.
// 여기서 정상적으로 PrincipalDetails가 return이 되면S
// 3. 그 principalDetails를 세션에 담고 (oauth2 방식과 다르게 Authentication 에 담지 않고 바로 세션에 담는다 ,,,,)
// -> 굳이 세션에 담는 이유: 세션에 담지 않으면 권한 관리가 되지 않기 떄문
// 하지만 권한관리가 필요없는 경우라면 (물론 그런 경우는 거의 없겠지만) principalDetails를 세션에 담지 않아도 된다.
// 4. jwt 토큰을 만들어서 응답해주면 됨.
// ------------------------------------------------------------) ━▶ try {} 영역안 주석인데 길어서 아래로 뺀 거임
// 제대로 로그인이 되지 않았다면 null을 반환한다.
return null;
}
// 실행 순서
// attemptAuthentication 실행 후 인증이 정상적으로 되었으면 successfulAuthentication 함수가 실행됨
// jwt 토큰을 만들어서 request 요청한 사용자에게 jwt 토큰을 response해주면 됨.
@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);
}
}
서버 재시작 후 로그인을 다시 시도해보면

정상적으로 로그인 성공 후 jwt 토큰 생성하는 메소드(오버라이드함) 인 successfulAuthentication이 실행된 것을 볼 수 있다!!!
자동으로 실행된다 별도로 try 영역 안에서 실행시키지 않고 메소드 오버라이드만 해주면 됨!!
--
추가
잘못된 계정으로 로그인 하면!!

successfulAuthentication 이 실행되지 않았다는 것을 알 수 있다!!
임의 토큰을 만들었었다..
다음 게시물에서는 진짜로 jwt 토큰을 만들어서 반환하는 식으로 해보겠다!!
'spring security' 카테고리의 다른 글
| spring security - #27 (최종) jwt 토큰 서버 구축하기 (0) | 2024.02.03 |
|---|---|
| spring security - #26 jwt 만들어서 응답하기 (0) | 2024.02.03 |
| spring security - #25 (1) jwt를 위해서 로그인 진행하기 (0) | 2024.01.28 |
| spring security - #24 jwt를 위해서 로그인 진행하기 (0) | 2024.01.28 |
| spring security - #23 임시 토큰 만들어서 테스트 진 (1) | 2024.01.28 |