#7 [스프링 스터디] 쇼핑몰 만들기 프로젝트 - 판매자/구매자 페이지 권한 설정 (Feat. sec:authorize)

쇼핑몰의 기능은 판매자와 구매자로 나누어 집니다.

브라우저에서 같은 메인 화면을 보더라도

  • 판매자상품 등록, 수정, 삭제, 판매관리
  • 구매자상품 구매, 장바구니, 마이페이지

의 기능을 사용할 수 있습니다.

AuthenticationEntryPoint 인터페이스 구현 클래스를 사용하여 인증되지 않은 사용자의 요청이 오면 "Unauthorized" 에러를 발생시키고, SecurityConfig 파일에서 HttpServletRequset 에 대해 security 를 처리하여 수행하는 방법이 있습니다. http.authorizeRequests.mvcMatchers("/seller/**").hasRole("ROLE_SELLER") 이런 식으로 작성하면 되지만 저는 이러한 방식이 아직은 어렵고 복잡하다고 느껴 스터디 팀원의 도움으로 감사하게도 조금 더 쉬운(?) 방식을 사용하여 권한을 설정하였습니다.

바로 Controller에서 if문을 활용하는 방식입니다.

이 방식은 유저 프로필 페이지에서 더 유용하게 쓰일 수 있으니 추후에 적용해 보아도 좋을 것 같습니다 :)

로그인을 하지 않은 유저, 구매자(ROLE_USER)로 로그인 한 유저, 판매자(ROLE_SELLER)로 로그인 한 유저로 각각 접속을 하면

<로그인 안 한 메인페이지>

<구매자 메인페이지>

<판매자 메인페이지>

이렇게 각각의 접근 권한에 따라 상단부의 메뉴 기능이 다른 메인페이지가 나와야 합니다.

로그인을 하지 않은 유저, 구매자(ROLE_USER)로 로그인 한 유저, 판매자(ROLE_SELLER)로 로그인 한 유저에 맞게 html 파일을 이렇게 3개 만들으면 됩니다.

사실 이렇게 파일을 나누면 중복되는 부분이 많습니다. 더 효율적인 방법으로는 main 이라는 html 파일 하나에 sec:authorize 을 써서 3개의 파일을 하나의 파일로 작성할 수도 있지만 이 방법은 조금 뒤에 설명하도록 하겠습니다.

    // 메인 페이지 (로그인 안 한 유저) /localhost:8080
    @GetMapping("/")
    public String mainPageNoneLogin(Model model) {
        // 로그인을 안 한 경우
        List<Item> items = itemService.allItemView();
        model.addAttribute("items", items);

        return "/main";
    }

    // 메인 페이지 (로그인 유저) - 판매자, 구매자 로 로그인
    @GetMapping("/main")
    public String mainPage(Model model, @AuthenticationPrincipal PrincipalDetails principalDetails) {
        if(principalDetails.getUser().getRole().equals("ROLE_SELLER")) {
            // 어드민, 판매자
            List<Item> items = itemService.allItemView();
            model.addAttribute("items", items);
            model.addAttribute("user", principalDetails.getUser());

            return "/seller/mainSeller";
        } else {
            // 일반 유저일 경우
            List<Item> items = itemService.allItemView();
            model.addAttribute("items", items);
            model.addAttribute("user", principalDetails.getUser());

            return "user/mainUser";
        }
   }

Controller에서 우선 로그인을 안 한 유저와 로그인을 한 유저로 나눌 수 있습니다. 그리고 또 로그인을 한 유저는 판매자와 구매자로 나누어집니다.

@AuthenticationPrincipal 어노테이션을 통해 PrincipalDetails 를 매개변수로 받습니다.

조건문으로 현재 로그인 한 유저의 role을 get 하여 비교합니다. return 문을 보면 판매자일 경우 mainSeller로, 구매자일 경우 mainUser로 가는 것을 볼 수 있습니다.

이 방식은 상품 등록, 수정, 삭제에도 동일하게 사용됩니다.

상품 등록, 수정, 삭제 기능은 role 이 ROLE_SELLER인 유저에게만 가능하게끔 해야 하기 때문입니다.

> sec:authorize

이제 sec:authorize 를 사용한 방식을 알아보겠습니다.

html에 sec:authorize를 사용하면 위처럼 main을 세 개로 나누지 않아도 됩니다. 먼저 main.html 파일 상단의 html 태그에

xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"

타임리프를 넣어줍니다!

그리고 권한을 따로 줘야하는 곳에 가서 sec:authorize 를 넣어주면 되는데요, main에서 로그인 버튼은 로그인을 하지 않은 유저에게만 보여야 합니다. 따라서

<form th:action="@{/signin}" sec:authorize="!isAuthenticated()">
                <button class="btn btn-outline-dark" type="submit">
                    로그인
                </button>
            </form>

sec:authorize="!isAuthenticated()" 를 넣어주어 로그인을 하지 않았을 때 로그인 버튼이 보이도록 설정합니다.

로그아웃의 경우에는 로그인을 한 유저에게만 보여야 합니다. 따라서

<form th:action="@{/logout}" method="post" sec:authorize="isAuthenticated()">
                <button class="btn btn-outline-dark" type="submit">
                    로그아웃
                </button>
            </form>

sec:authorize="isAuthenticated()" 를 넣어주면 되겠지요!

이 외에 sec:authorize="hasRole('ROLE_USER')"sec:authorize="hasRole('ROLE_SELLER')" 도 있습니다.

예를 들어 상품 등록 버튼에는 ROLE_SELLER를, 마이페이지 버튼에는 ROLE_USER를 사용합니다.

이렇게 sec:authorize를 사용하면 html 파일을 나누어 관리하는 것이 아닌 하나의 파일에서 관리할 수 있어 편리합니다!

저는 처음에 이 기능을 몰라서 html을 여러개 만들어 하나를 고치면 다른 파일도 고쳐야 하는 번거로움이 있었는데, sec:authorize를 사용하여 더 수월하게 코드를 수정할 수 있을 것 같습니다 :)

좋은 웹페이지 즐겨찾기