inblog logo
|
goho
    스프링부트

    스프링 인증블로그 (1) 로그인, 필터

    gov's avatar
    gov
    Nov 27, 2024
    스프링 인증블로그 (1) 로그인, 필터
    Contents
    목표세팅1. 의존성 세팅2. 클래스 의존성기능 구현1. 로그인2. 필터
    💡
    • 인증/인가
    • 필터

    목표

    • 인증(Authentication) 사용자가 누구인지 확인하는 과정 (ex. 로그인)
    • 인가(Authorization) 인증된 사용자가 어떤 권한을 가지는지 확인하는 과정 (ex. 관리자 권한)
    인증은 "누구인가?", 인가는 "무엇을 할 수 있는가?"에 초점
    • 필터 (Filter)
      • 요청(Request)와 응답(Response)에 대해 중간에서 처리 로직을 수행하는 인터페이스
      • 주요 용도: 인증, 로깅, CORS 처리 등
    • 연관관계 (조인)
      • 연관관계: 엔티티 간의 관계를 설정 (ex. 1:1, 1:N, N:M)
      • 조인: 관계형 DB에서 연관된 데이터를 함께 조회하기 위해 사용하는 SQL 연산
      • 스프링 JPA에서 연관관계를 설정하면, @OneToOne, @ManyToOne 등으로 조인을 자동화
     

    세팅

    1. 의존성 세팅

    notion image

    2. 클래스 의존성

    1. 어플리케이션
    1. 패키지 및 클래스 생성과 의존성
      1. 레파지토리(엔티티), 서비스(레파지토리), 컨트롤러(서비스)
    1. 레파지토리 쿼리문 작성 > 만든 쿼리문 테스트

    기능 구현

    1. 로그인

    섹션 흐름
    @RequiredArgsConstructor @Repository public class UserRepository { // DB조회해서 가져오기 private final EntityManager em; public User findByUsername(String username) { // 유저클래스로 바로 캐스팅 Query q = em.createQuery("select u from User u where u.username = :username", User.class); // JPQL쿼리문 q.setParameter("username", username); try { return (User) q.getSingleResult(); } catch (RuntimeException e) { throw new RuntimeException("아이디 혹은 패스워드가 일치하지 않습니다"); } } } ---- public class UserRequest { @Data public class LoginDTO { private String username; private String password; } } ---- @RequiredArgsConstructor @Controller public class UserController { private final UserSevice userService; // 다른 방법을 써도 final 반드시 붙이기 private final HttpSession session; @PostMapping("/user") public String login(UserRequest.LoginDTO loginDTO) { User sessionUser = userService.로그인(loginDTO); session.setAttribute("sessionUser", sessionUser); return "redirect:/"; // 로그인되면 메인페이지 이동 } @ResponseBody @GetMapping("/test/auth") public String testAuth() { User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null) { return "인증안됨"; } return "인증됨 : "+sessionUser.getUsername(); } } ---- @RequiredArgsConstructor @Service public class UserSevice { private final UserRepository userRepository; public User 로그인(UserRequest.LoginDTO loginDTO) { User userPS = userRepository.findByUsername(loginDTO.getUsername()); if(!userPS.getPassword().equals(loginDTO.getPassword())) { throw new RuntimeException("아이디 혹은 패스워드가 일치하지 않습니다"); // 로그를 남겨서 서버에 패스워드가 실패 카운팅 } return userPS; } }
     

    2. 필터

    💡
    필터 정의
    • 필터 클래스 생성 FilterConfig는 AuthenticationFilter를 애플리케이션에 적용하기 위한 설정을 담당하며, AuthenticationFilter는 해당 설정을 기반으로 인증 검사를 수행.
    AuthenticationFilter 클래스
    public class AuthenticationFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; HttpSession session = req.getSession(); // 리퀘스트 객체에서 세션 가져옴 User sessionUser = (User) session.getAttribute("sessionUser"); if(sessionUser != null) { resp.sendRedirect("/login-form"); } else { chain.doFilter(request, response); // null이 아니면 다음 필터로 } } }
    역할
    • HTTP 요청에서 세션 정보를 확인해 인증 여부를 판단.
    • 인증되지 않은 사용자는 로그인 화면(/login-form)으로 리다이렉트.
    • 인증된 사용자는 요청 처리를 다음 필터나 컨트롤러로 넘김.
     
    동작 흐름
    1. 요청/응답 객체 형변환
      1. HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response;
        전달받은 ServletRequest와 ServletResponse를 각각 HTTP 프로토콜에 맞게 HttpServletRequest와 HttpServletResponse로 형변환.
    1. 세션 객체 가져오기
      1. HttpSession session = req.getSession(); User sessionUser = (User) session.getAttribute("sessionUser")
        • req.getSession()으로 현재 요청의 세션 객체를 가져옴.
        • 세션에서 sessionUser 속성을 조회해 유저 정보를 확인.
    1. 인증 여부 확인
      1. if(sessionUser != null) { resp.sendRedirect("/login-form"); } else { chain.doFilter(request, response); }
        sessionUser != null (세션에 유저 정보가 있음):
        • 이미 로그인된 상태 → **"/login-form"**으로 리다이렉트.이는 로그인 상태에서 불필요한 접근을 막는 용도.
        sessionUser == null (세션에 유저 정보가 없음):
        • 로그인되지 않은 상태 → 다음 필터 또는 컨트롤러로 요청 전달 (chain.doFilter()).
    FilterConfig 클래스
    @Configuration // 메서드 때리기 public class FilterConfig { @Bean // 리턴값이 IoC에 등록됨 public FilterRegistrationBean addAuthFilter() { FilterRegistrationBean rg = new FilterRegistrationBean(); rg.setFilter(new AuthenticationFilter()); rg.addUrlPatterns("/board/*"); // 주소가 board 이면 허용 rg.addUrlPatterns("/user/*"); rg.setOrder(1); // 필터 순서 정하기 // 해당 메서드 실행시, 리턴되는 객체를 IOC 컨테이너에 등록 return rg; } }
    전체 흐름
    1. 애플리케이션 시작 시 필터 등록
        • FilterConfig:
          • addAuthFilter() 메서드 실행:
            • 새로운 FilterRegistrationBean 생성.
            • AuthenticationFilter를 필터로 설정.
            • URL 패턴 (/board/*, /user/*)에 대해 필터가 적용되도록 지정.
            • 필터 실행 순서를 설정 (setOrder(1)).
    1. 클라이언트 요청
      1. 클라이언트가 /board/* 또는 /user/* 경로로 HTTP 요청을 보냄.
    1. 필터 실행
    1. 4단계: 컨트롤러 처리
        • 필터를 통과한 요청은 컨트롤러(BoardController 등)로 전달.
        • 컨트롤러는 추가 비즈니스 로직을 처리.
    1. 응답 반환
      1. 컨트롤러에서 처리한 결과를 클라이언트에 반환.
    Share article

    goho

    RSS·Powered by Inblog