원지의 개발
article thumbnail
728x90

Connectionsless Protocol

  • 웹 서비스는 HTTP 프로토콜 기반, 요청(request)에 대한 응답(response) 후 관계를 끊음
  • 인증되지 않은 사용자는 모든 페이지에서 인증과정을 거쳐야 하는데 지속적인 인증 수단으로 세션과 쿠키를 사용

session

스프링 MVC의 세션 2가지

public String updatePage(HttpServletRequest request) {...}
  • HtteServletRequest: 파라미터로 HtteServletRequest를 받을 후 getSession()을 세션 얻음
public String MyPage(HttpSession session) {...}
  • Httpsession: 파라미터로 Httpsession을 받아 세션 사용
session 메서드 기능
getId() 세션 ID 반환
setAttribute() 세션 객체에 속성 저장
getAttribute() 세션 객체에 저장된 속성을 반환
removeAttribute() 세션 객체에 저장된 속성을 제거
setMaxInactiveInterval() 세션 객체의 유지시간 설정
getMaxInactiveInterval() 세션 객체의 유지시간 반환
invalidate() 세션 객체의 모든 정보 삭제

2022.11.30 - [Server/JSP] - [JSP] 내장 객체(request, response, out, application), cookie, session, path

 

[JSP] 내장 객체(request, response, out, application), cookie, session, path

JSP 내장 객체 jsp 파일 내에 객체 생성 없이 바로 사용할 수 있는 객체 jsp 컨테이너에 의해 서블릿으로 변환될 때 자동으로 객체 생성 Requset 웹 브라우저를 통해 서버에 어떤 정보를 요청 요청 정

j-won950101.tistory.com


redirect

출처: chat gpt


로그인 2가지 - interceptor, security

Interceptor, 권한처리

HandlerInterceptor 인터페이스를 상속받은 클래스를 인터셉터로 등록
preHandle() 컨트롤러 진입 전에 실행 많이 사용
postHandle() 컨트롤러 수행 후에 실행  
afterCompletion() 화면으로 가기 직전에 수행 굳이 사용x

실습

  1. 인터셉터 클래스에서 HandlerInterceptor를 오버라이딩, return true이면 컨트롤러 실행
  2. WebConfig(스프링 설정 파일)에서 WebMvcConfigurer를 오버라이딩함
    WebMvcConfigurer가 할 수 있게 해줌
  3. 위에서 설정한 인터셉터 클래스를 빈으로 생성
  4. addInterceptors를 오버라이딩하여 메서드 실행

여러 핸들러를 사용하려면 빈을 생성하고 각기 다르게 등록하면 됨

login - mypage - info

@Controller
@RequestMapping("/user")
public class UserController {

	@GetMapping("/login") //화면 띄우는 거고
	public String login() {
		return "user/login";	
	}
	
	//로그인 기능
	@PostMapping("/login") //포스트로 로그인 하는거
	public String loginForm(UsersVO vo, HttpSession session) {
		
		//select * from 유저 where id=? and pw=? 날리면 select된 값이 넘어옴, 없으면 값이 없고(null값 나타냄)
		//System.out.println(vo.toString()); 확인
		
		//서비스 영역 호출 (로그인 성공)
		UsersVO userVO = new UsersVO();
		userVO.setId("aaa");
		userVO.setName("홍길동"); //성공이라고 가정 - 값이 있을 것임
		
		//로그인 성공 - 세션을 이용해서 인증값
		if(userVO != null) { //로그인 성공했다면
			session.setAttribute("user_id", userVO.getId()); //토큰
			return "redirect:/user/mypage"; //로그인 성공, 리다이렉트를 이용해야 세션 식별 가능
		} 
		return "redirect:/user/login"; //실패시에 그냥 다시 로그인 페이지
	}
	
	//특정 유저들만 접근할 수 있는 페이지
	@GetMapping("/mypage")
	public String mypage(HttpSession session) {
		
		//세션 검사
		if(session.getAttribute("user_id") == null) {
			return "redirect:/user/login";
		}
		System.out.println("마이페이지 컨트롤러 실행");
		return "user/mypage";
	}
	
	@GetMapping("info")
	public String info(HttpSession session) {
		if(session.getAttribute("user_id") == null) {
			return "redirect:/user/login";
		}
		return "user/info";
	}
	
}

1. HandlerInterceptor - preHandle

public class UserAuthHandler implements HandlerInterceptor{
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		System.out.println("인터셉터 실행");
		
		//현재 세션을 얻음
		HttpSession session = request.getSession();
		String user_id = (String)session.getAttribute("user_id");
		
		//System.out.println(user_id);
		if(user_id == null) { //로그인이 안 됨
			response.sendRedirect(request.getContextPath() + "/user/login"); //로그인 페이지로 리디렉션
			return false; //컨트롤러를 실행하지 않음
		}
		return true; //컨트롤러 실행
	}
}
  • 기본 컨텍스트일 경우(root context) request.getContextPath() 공백
  • 경로를 맞출 경우에는 그게 나옴
  • 그래서 리다이렉트로 /user/login으로 바로 들어감

2. WebConfig

@Configuration //개별적인 스프링 빈 설정 파일, spring에서 servlet-context.xml로 썼던거
public class WebConfig implements WebMvcConfigurer{
	
	@Bean
	public UserAuthHandler userAuthHandler() {
		return new UserAuthHandler(); //UserAuthHandler 빈 생성, 등록
	}
	
	@Bean
	public UserSuccessHandler userSuccessHandler() {
		return new UserSuccessHandler(); //UserSuccessHandler 빈 생성, 등록
	}
	
	//WebMvcConfigurer 클래스가 제공해주는 인터셉터 추가 함수 - 오버라이딩 되면 이 메서드 먼저 실행, 이거 쓰면 알아서 스프링으로 던져줌
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
			registry.addInterceptor(userAuthHandler())
					//경로 정해서 포함 시킬수도 있음 (캡쳐)
					.addPathPatterns("/user/*") //패스경로 포함 (전체)
					.excludePathPatterns("/user/login") //패스경로 제외
					; //핸들러 인터셉터 타입이 들어감
			
			//경로별로 인터셉터를 다르게 등록 - 여러개 더 추가해서 사용 가능
			//registry.addInterceptor(null);
			registry.addInterceptor(userSuccessHandler())
					.addPathPatterns("/user/*");
	}
}
  • /user/* 유저의 모든 경로 다 잡음, login 제외(실패시 로그인 페이지로 리디렉션 해야하니)

3. HandlerInterceptor - postHandle

public class UserSuccessHandler implements HandlerInterceptor{
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		
		//modelAndView은 컨트롤러에서 model에 담은 데이터도 확인 가능
		System.out.println("포스트핸들러:" + request.getRequestURI());
	}
}

4. 결과

BootMyweb

1. UserAuthHandler- preHandle

  • 사용자 인증, 권한 같은 경우 요청이 컨트롤러에 전달되기 전 작업 수행
public class UserAuthHandler implements HandlerInterceptor{
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		System.out.println("인터셉터 실행");
		
		//현재 세션을 얻음
		HttpSession session = request.getSession();
		String user_id = (String)session.getAttribute("user_id");
		
		//System.out.println(user_id);
		if(user_id == null) { //로그인이 안 됨
			response.sendRedirect(request.getContextPath() + "/user/login"); //로그인 페이지로 리디렉션
			return false; //컨트롤러를 실행하지 않음
		}
		return true; //컨트롤러 실행
	}
}

2. WebConfig

@Configuration //스프링 설정 파일
public class WebConfig implements WebMvcConfigurer{

	//프리핸들러
	@Bean
	public UserAuthHandler userAuthHandler() {
		return new UserAuthHandler();
	}
	
	//포스트핸들러
	@Bean
	public MenuHandler menuHandler() {
		return new MenuHandler();
	}
	
	//인터셉터 추가
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(userAuthHandler())
				.addPathPatterns("/main")
				.addPathPatterns("/product/*") //product 시작하는 경로 다 추가
				.addPathPatterns("/user/*") //user 시작하는 경로 다 추가
				.excludePathPatterns("/user/login") //login 경로 제외
				.excludePathPatterns("/user/join"); //join 경로 제외
		
				//.addPathPatterns("/**") //**해야 다른 /product까지 잡힘, *만 있으면 바로 하위의 /user만 잡힘 
				//.excludePathPatterns("/user/login")
				//.excludePathPatterns("/user/join")
				//.excludePathPatterns("/js/*")
				//.excludePathPatterns("/css/*")
				//.excludePathPatterns("/img/*");
				//REST API 패스에서 제외..? 해야함
		
		registry.addInterceptor(menuHandler())
				.addPathPatterns("/main")
				.addPathPatterns("/product/*")
				.addPathPatterns("/user/*");
	}
}
  • userAuthHandler() 부분 주석 처리 안하면 무조건 로그인 해야함 (실습시 주석처리)

3. MenuHandler - postHandle

  • 컨트롤러가 처리한 결과에 대한 후속 작업 수행
  • 컨트롤러가 생성한 모델을 수정하거나 뷰를 렌더링 하기 전에 추가적인 작업 수행
  • 메뉴는 모든 요청에 대해 처리하므로 Interceptor에서 처리
  • 혹은 로그인 했을 경우(회원수정, 로그아웃)와 아닌 경우(회원가입, 로그인)로 나눌 때
  • 메뉴 인터셉터는 주로 요청 URI를 기반으로 메뉴나 레이아웃 관련된 작업을 수행
public class MenuHandler implements HandlerInterceptor {

	//메뉴핸들러
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		
		String uri = request.getRequestURI(); //전체주소 - 포트번호, /product/productList
		System.out.println(uri);
		request.setAttribute("uri", uri); //request 객체에 저장(키, 값)
		
		// 요청 URI에 따라 다른 로직 수행
        if (uri.startsWith("/product")) {
            // "/admin"으로 시작하는 요청의 경우 특별한 작업 수행
            System.out.println("상품 페이지 요청입니다.");
            // 추가적인 로직 수행 가능
        } else {
            // 그 외의 경우 기본 로직 수행
            System.out.println("사용자 페이지 요청입니다.");
            // 기본적인 로직 수행
        }
	}
}

  • WebConfig에서 path 등록하면 핸들러에 uri값 가지고 들어옴
  • request.setAttribute("uri", uri); 으로 설정

  • Thymeleaf를 사용하여 JavaScript에 URI 값 전달
  • addPathPatterns로 /main (기본 /이었던거 /main으로 바꿈) 등록했기 때문에 모든 화면에서 사용 가능
<script th:inline="javascript">
    var uri = JSON.parse('[[${uri}]]'); //postHandler에서 보내주는 uri

    console.log(JSON.parse('[[${uri}]]')) //필요한 값을 가지고 나갈 수 있음
</script>

4. 메뉴 선택 유지

sub_menu에 display:block,
sub_menu ▶ a링크에 on 클래스,
sub_menu_toggle ▶ a에 sub_menu_selectz 클래스

<script th:inline="javascript">
	console.log(JSON.parse('[[${uri}]]')); //필요한 값을 가지고 나갈 수 있음

	/* 
		메뉴선택 유지 - 
		sub_menu에 display:block,
		sub_menu ▶ a링크에 on 클래스,
		sub_menu_toggle ▶ a에 sub_menu_selectz 클래스
	*/
	var menu = JSON.parse('[[${uri}]]'); //postHandler에서 보내주는 uri
	
	
	//1. 반복 안 돌리기
	console.log($("a[href*='" + menu + "']"));
	$("a[href*='" + menu + "']").addClass("on");
	//이 아래처럼 쭉쭉쭉 같이하면 반복 안돌리고 가능

	//2. 반복 돌리기	
	$(".sub_menu a").each(function(index, item) { //반복을 돌려서 콜백함수로
		//console.log(index, item); //a태그
		//console.log($(item));

		//attr - 속성값 가져오기
		//console.log($(item).attr("href"));
		 
		if( $(item).attr("href").includes(menu) ) {
			//console.log("확인");
			$(item).addClass("on"); //a태그에 on클래스 추가 - 위 주석에서 a링크에 on클래스 부분
			$(item).closest(".sub_menu").css("display", "block"); //위 주석에서 display: block 부분
			$(item).closest(".sub_menu").prev().addClass("sub_menu_select"); //sub_menu쪽 세가지 작업 처리 
		}
	})
</script>

5. 확인

  • session으로 admin을 설정해 놨기 때문에 UserAuthHandler 인터셉터 실행
  • 메뉴에서 상품등록을 눌렀을 경우 MenuHandler 실행

오늘 하루

더보기

기억에 남는 부분

 

어려운 부분

 

문제 해결 부분

 

728x90
profile

원지의 개발

@원지다

250x250