JAN's History
JWT 구현하기 : 로그인 요청 시 JWT 응답(Response) 본문
RestApiController
- 로그인 기능을 구현하기 전 회원가입을 먼저 진행해보자
@PostMapping("join")
public String join(@RequestBody User user) {
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
user.setRoles("ROLE_USER");
userRepository.save(user);
return "회원가입완료";
}
SecurityConfig에 BCryptPasswordEncoder Bean으로 등록
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
Postman 으로 회원가입 요청
JwtAuthenticationFilter 수정
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
System.out.println("JWT AuthenticationFilter : 로그인 시도중");
//1. request에 username, password를 받아서
try {
// BufferedReader br = request.getReader();
//
// String input = null;
// while((input = br.readLine())!= null){
// System.out.println(input);
// }
// System.out.println(request.getInputStream().toString()); //stream안에 username와 id ..이 담겨있음
ObjectMapper om = new ObjectMapper(); //ObjectMapper가 **<json>** 데이터를 알아서 파싱해줌
User user = om.readValue(request.getInputStream(), User.class); //user model에 알아서 파싱해준다 완전 GOOOD!!
System.out.println(user); //잘 파싱된 것을 확인함.
//2. user model token화 하기(원래 자동으로 해주는데 우리가 Filter 구현한 거라서 해줘야함)
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
//3. PrincipalDetailsService의 loadUserByUsername()함수가 실행됨
//loadUserByUsername 함수가 실행된 후 정상이면 authentication이 리턴됨
// 즉 DB에 있는 username과 password가 일치한다는 뜻.
Authentication authentication = authenticationManager.authenticate(authenticationToken);
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
System.out.println("로그인 완료" + principalDetails.getUser().getUsername()); //꺼냈을 때 값이 있으면 로그인이 정상적으로 되었다는 뜻
//authentication 객체가 session 영역에 저장을 해야하는데 그 방법이 return을 해주면 됨
//리턴을 해주는 이유는 권한 관리를 security가 대신 해주기 때문에 편하려고 하는 것!!
//굳이 jwt 토큰을 사용하면서 세션을 만들 이유가 없.지.만, 단지 권한 처리 때문에 sessin을 넣어 주는 것이다.
return authentication; // 이 값이 세션에 저장됨
} catch (IOException e) {
throw new RuntimeException(e);
}
}
- /login 요청을 하면 ObjectMapper가 JSON 데이터를 user entity로 매핑해 데이터를 알아서 파싱해준다!
- temptAuthentication실행 후 인증이 정상적으로 되었다면 successfulAuthentication가 실행된다
➡️정상적으로 파싱된 모습
JwtAuthenticationFilter SucessfulAuthentication 에 메서드 추가
@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를 생성하여 request한 사용자에게 토큰을 반환해주면 된다.
- 일단 정상 동작하는지 확인해보자
➡️정상적으로 실행됨
JwtAuthenticationFilter->SucessfulAuthentication->JWT 토큰 생성 관련 코드 추가
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
System.out.println("successfulAuthentication 실행됨 : 인증 완료!!");
PrincipalDetails principalDetails = (PrincipalDetails) authResult.getPrincipal(); //authResult이 Authentication의 객체
//RSA 방식은 아니고 Hash암호 방식
String jwtToken = JWT.create()
.withSubject("cos토큰")
.withExpiresAt(new Date(System.currentTimeMillis()+(60000)*10)) //10분
.withClaim("id", principalDetails.getUser().getId())
.withClaim("username", principalDetails.getUser().getUsername())
.sign(Algorithm.HMAC512("cos")); //server만 알고있는 secret 값
response.addHeader("Authorization", "Bearer "+jwtToken);
}
- 여기서 인자값으로 받은 authResult는 JwtAuthenticationFilter에서 생성된 Authentication의 객체다.
- 이제 다시 포스트맨으로 요청을 보내보자!
- header에 Authorization의 value로 토큰이 들어가있다!
- JWT 토큰 생성 완료
막간을 이용한 세션 방식 vs jwt방식
- 세션 방식
- 로그인 시도 후 성공하면 서버쪽에서 세션을 생성하고 서버에 저장을 한 후, 세션 id를 쿠키에 담아 클라이언트에게 함께 보낸다
- 이후 클라이언트가 다시 요청을 보내면 서버는 쿠키값의 세션 id가 유효한지 서버의 세션 id와 비교하고, 인증이 필요한 페이지로 접근하게 하면 된다.
- JWT방식
- 로그인 시도 후 성공하면 서버쪽에서 jwt를 생성하고, jwt를 클라이언트에게 보낸다
- 이후 클라이언트가 다시 요청을 할 때 jwt를 함께 보내고, 서버는 jwt가 유효한지 필터를 이용해 판단을 한다.
'JWT' 카테고리의 다른 글
[최종] JWT 구현하기 : 생성하고 인증하기 (0) | 2024.07.13 |
---|---|
JWT를 구현할 때 권한관리를 하기 위해 Authentication을 return 해야하는 이유 (0) | 2024.07.08 |
JWT 임시 토큰으로 필터 테스트 (0) | 2024.07.06 |
JWT를 구현하기전, Filter 등록 테스트 (0) | 2024.07.04 |
JWT를 구현하기전, 인증/인가 동작 원리: FilterChain을 이해해보자! (0) | 2024.07.03 |