24.08.28

윤지현·2024년 8월 28일

TIL

목록 보기
52/75

오늘의 루틴

  • 개인과제 8단계 완료 및 9~10단계 시도 (O)
  • 공부한 내용 복습 (O)

8단계를 하려는데 이젠 로그인도 해서 인증도 해야하네....

  • 8단계 : 로그인

🔻 설명

  • JWT를 활용해 로그인 기능을 구현합니다.
  • 필터를 활용해 인증 처리를 할 수 있습니다.

🔻 조건

  • 이메일과 비밀번호를 활용해 로그인 기능을 구현합니다.
    • 로그인 성공 시 JWT 발급 후 반환합니다.
  • 모든 요청에서 토큰을 활용하여 인증 처리를 합니다.
    • 토큰은 Header에 추가합니다.
  • 회원가입과 로그인은 인증 처리에서 제외합니다.

⚠️ 예외 처리

  • 로그인 시 이메일과 비밀번호가 일치하지 않을 경우 401을 반환합니다.
  • 토큰이 없는 경우 400을 반환합니다.
  • 유효 기간이 만료된 토큰의 경우 401을 반환합니다.

먼저 JWT를 검증하고 인증할 AuthFilter.java와 요청과 응답 사이의 로그를 관리할 LoggingFilter.java를 생성한다.


1. AuthFilter.java

@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        String url = httpServletRequest.getRequestURI();
        String tokenValue = jwtUtil.getTokenFromRequest(httpServletRequest);

        log.info("Request URL: {}", url);
        log.info("Extracted Token Value: {}", tokenValue);

        if (StringUtils.hasText(url) &&
                (url.startsWith("/api/auth/signup") || url.startsWith("/api/auth/login"))
        ) {
            log.info("인증 처리를 하지 않는 URL : " + url);
            chain.doFilter(request, response); // 다음 Filter로 이동
        } else {
            if (StringUtils.hasText(tokenValue)) {
                // JWT 토큰 substring
                String token = jwtUtil.substringToken(tokenValue);

                // 토큰 검증
                if (!jwtUtil.validateToken(token)) {
                    httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
                    httpServletResponse.getWriter().write("The token is either invalid or expired");
                    return;
                }

                // 토큰에서 사용자 정보 가져오기
                Claims info = jwtUtil.getUserInfoFromToken(token);

                User user = userRepository.findByUsername(info.getSubject()).orElseThrow(() ->
                        new NullPointerException("Not Found User")
                );

                request.setAttribute("user", user);
                chain.doFilter(request, response); // 다음 Filter로 이동
            } else {
                httpServletResponse.setStatus(HttpStatus.BAD_REQUEST.value());
                httpServletResponse.getWriter().write("Not Found Token");
                return;
            }
        }
    }

2. LoggingFilter.java

@Slf4j(topic = "LoggingFilter")
@Component
@Order(1)
public class LoggingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 전처리
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String url = httpServletRequest.getRequestURI();
        log.info(url);

        chain.doFilter(request, response); // 다음 Filter 로 이동

        // 후처리
        log.info("비즈니스 로직 완료");
    }
}

이번에는 로그인 할 때 사용할 dto를 생성


1. LoginRequestDto.java

@Getter
public class LoginRequestDto {
    private String email;
    private String password;
}

2. LoginResponseDto.java

@Getter
@Setter
@NoArgsConstructor
public class LoginResponseDto {
    private String msg;
    private int statusCode;

    public LoginResponseDto(String msg, int statusCode) {
        this.msg = msg;
        this.statusCode = statusCode;
    }
}

회원가입하고 로그인할 AuthController.java를 생성한다.


1. AuthController.java

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    private final UserService userService;
    private final JwtUtil jwtUtil;

    public AuthController(UserService userService, JwtUtil jwtUtil) {
        this.userService = userService;
        this.jwtUtil = jwtUtil;
    }

    @PostMapping("/signup")
    public ResponseEntity<?> signup(@RequestBody UserRequestDto userRequestDto) {
        try {
            UserResponseDto userResponseDto = userService.createUser(userRequestDto);
            return ResponseEntity.status(HttpStatus.CREATED).body(userResponseDto);
        } catch (Exception e) {
            // 예외 로그 기록
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("회원가입 실패: " + e.getMessage());
        }
    }


    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequestDto loginRequestDto, HttpServletResponse response) {
        try {
            User user = userService.authenticate(loginRequestDto.getEmail(), loginRequestDto.getPassword());
            String token = jwtUtil.createToken(user.getUsername());

            // JWT를 Header에 추가
            response.addHeader(HttpHeaders.AUTHORIZATION, token);

            // 응답 본문에 메시지와 상태 코드 반환
            return ResponseEntity.ok(new LoginResponseDto("로그인 성공", 200));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid email or password");
        }
    }
}

이러면 잘 되는데 UserService에서도 유저를 생성할 수 있어서 한 번 고민을 해봐야 될 것 같다.

profile
첫 시작

0개의 댓글