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
redirect
로그인 2가지 - interceptor, security
Interceptor, 권한처리
HandlerInterceptor 인터페이스를 상속받은 클래스를 인터셉터로 등록 | ||
preHandle() | 컨트롤러 진입 전에 실행 | 많이 사용 |
postHandle() | 컨트롤러 수행 후에 실행 | |
afterCompletion() | 화면으로 가기 직전에 수행 | 굳이 사용x |
실습
- 인터셉터 클래스에서 HandlerInterceptor를 오버라이딩, return true이면 컨트롤러 실행
- WebConfig(스프링 설정 파일)에서 WebMvcConfigurer를 오버라이딩함
▶ WebMvcConfigurer가 할 수 있게 해줌 - 위에서 설정한 인터셉터 클래스를 빈으로 생성
- 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
'Server > Spring boot' 카테고리의 다른 글
[인프런] 스프링 부트와 JPA 활용1 - 환경설정 및 도메인 분석 설계 (0) | 2024.09.05 |
---|---|
[Spring Boot] BootMyweb (5) - 자바측 API, Gson, 카카오로그인 (0) | 2023.02.23 |
[Spring Boot] BootMyweb (3) - 파일 업로드, 불러오기, selectKey (0) | 2023.02.21 |
[Spring Boot] RestAPI, 부메랑, @RestController, @RequestBody, CrossOrigin (0) | 2023.02.16 |
[Spring Boot] BootMyweb (1) - 관리자 홈페이지 / 기본 연결, 검색&Paging (0) | 2023.02.15 |