프로젝트

[JPA/Thymeleaf] 게시글 작성자만 수정 권한 가지기

ummchicken 2023. 2. 18. 16:20

간단한 게시판 만들기 중...

 

계속 보다보니까 앞뒤가 안 맞는 것들이 보인다.

 

이번엔, 게시글 작성자만 수정할 수 있게 하는 기능을 추가했다.

정확히는 추가라기 보다는, 기존 기능을 수정했다고 보는 게 맞을 것 같다.

 

 

[수정 전]

  • ADMIN 권한을 가진 user만 게시글을 등록하고 수정할 수 있음
    • 나머지는 조회만 가능
  • 하지만 ADMIN 권한만 가지고 있다면, 본인이 등록한 게시물이 아니어도 수정할 수 있음

 

 

[수정 후]

  • 본인이 등록한 게시물만 수정할 수 있음

 

 


 

✔️ 수정 순서

  1. 게시물 Dto에 username 속성 추가
  2. 게시물 엔티티의 createBy를 가져와 username에 저장한다.

 

 

Service를 수정하기 전, 

게시물을 조회하는 Controller의 코드를 보자.

[Controller]

// 게시물 상세보기
@GetMapping(value = "/recipe/{recipeId}")
public String recipeDtl(Model model, @PathVariable("recipeId") Long recipeId) {
    RecipeFormDto recipeFormDto = recipeService.getRecipeDtl(recipeId);
    
    recipeService.updateView(recipeId); // views ++
    model.addAttribute("recipe", recipeFormDto);

    return "recipe/recipeDtl";
}
  • Service에서 게시물 Dto(위의 코드에선 recipeFormDto)를 조회한 결과인 Dto를 View에 넘긴다.

 

 

 

이제 코드를 수정해보자.

먼저 게시물 Dto에 username을 추가한다. (엔티티는 그대로 놔둠)

/**
 * 게시물 데이터 정보를 전달하는 DTO
 * */
@Getter
@Setter
public class RecipeFormDto {

    ...

    // 작성자 정보 저장 : createBy
    private String username;

    ...

}

 

 

 

그 다음 Service에 추가해보자.

[기존 Service]

/**
 * 등록된 게시물을 불러옴
 * */
@Transactional(readOnly = true)
public RecipeFormDto getRecipeDtl(Long recipeId){

    ...
    
    Recipe recipe = recipeRepository.findById(recipeId)
            .orElseThrow(EntityNotFoundException::new);
            
    ...

    return recipeFormDto;
}

 

 

[수정 후 Service]

/**
 * 등록된 게시물을 불러옴
 * */
@Transactional(readOnly = true)
public RecipeFormDto getRecipeDtl(Long recipeId){

    ...
    
    Recipe recipe = recipeRepository.findById(recipeId)
            .orElseThrow(EntityNotFoundException::new);
            
    if(recipe.getCreatedBy() != null) {
        recipeFormDto.setUsername(recipe.getCreatedBy());
    }

    return recipeFormDto;
}
  1. 게시물 엔티티의 등록자(CreateBy)를 조회한다.
  2. 조회 결과가 있으면(!= null) 게시물 Dto의 username에 엔티티의 등록자(CreateBy)를 세팅한다.

 

 

 

다음은 ViewPage에 추가한다.

난 Thymeleaf로 했다.

 

먼저 들어가기 전, 현재 로그인 한 user와 게시물 등록자의 정보를 테스트 해보고 싶다.

[Thymeleaf]

<b>Authenticated username:</b>
<div sec:authentication="name"></div>
<div class="h4" th:text="${recipe.username}"></div>

 

 

위의 코드를 추가하면 결과 화면은 다음과 같이 나온다.

  • Authenticated username : 현재 로그인한 사용자의 정보이다.
    • 스프링 시큐리티에서는 username이 사용자의 이름이 아닌 사용자의 ID이다.
    • 나의 경우에는 username을 email로 설정했다.
      • email 필드를 unique로 지정했기에 가능한 것이다.
      • 이 부분은 각자의 엔티티 조건에 맞춰 코드를 변경한다.
  • 나의 경우인 recipe.username은 위에서 설정한 게시물 등록자이다.

 

 

더 자세한 정보는 다음과 같다. (출처)

<!--ROLE_USER 권한을 갖는다면 이 글이 보임-->
<h1 sec:authorize="hasRole('ADMIN')">Has admin Role</h1>

<!--ROLE_ADMIN 권한을 갖는다면 이 글이 보임-->
<h1 sec:authorize="hasRole('USER')">Has user Role</h1> 

<!--어떤 권한이건 상관없이 인증이 되었다면 이 글이 보임-->
<div sec:authorize="isAuthenticated()">
    Only Authenticated user can see this Text
</div>

<!--인증시 사용된 객체에 대한 정보-->
<b>Authenticated DTO:</b>
<div sec:authentication="principal"></div>

<!--인증시 사용된 객체의 Username (ID)-->
<b>Authenticated username:</b>
<div sec:authentication="name"></div>

<!--객체의 권한-->
<b>Authenticated user role:</b>
<div sec:authentication="principal.authorities"></div>

 

 

 

테스트를 통한 확인은 끝났으니, 본격적으로 view 코드를 추가해보자.

[Thymeleaf]

<div class="text-right" sec:authorize="hasAnyAuthority('ROLE_ADMIN')"
     th:if="${#authentication.principal.username} == ${recipe.username}" >
    <button type="button" class="btn btn-light border border-primary btn-lg"
            th:onclick="'location.href=\'/admin/recipe/'+ @{${recipe.id}}+ '\''">게시물 수정</button>
</div>
  • sec:authorize="hasAnyAuthority('ROLE_ADMIN')"
    • ADMIN 권한을 가진 사람만 div가 보인다.
  • th:if="${#authentication.principal.username} == ${recipe.username}"
    • 위에서 확인한 스프링 시큐리티의 username과 게시물 등록자가 같다면, div가 보인다.
  • 즉, 위의 두 조건을 만족한 사람만 '게시물 수정' 버튼이 보이는 것이다.

 

 

 

코드를 모두 수정했으니 

마지막으로 결과를 확인해보자.

[조건]

  • aaa@naver.com은 test1 게시물을 등록한다.
  • bbb@naver.com은 test2, test3 게시물을 등록한다.

 

[예상 결과]

  • 로그인을 하지 않은 사용자에겐, '수정' 버튼이 보이지 않는다.
  • aaa@naver.com은 test1 게시물에 '수정' 버튼이 보인다.
  • aaa@naver.com은 test2, test3 게시물에 '수정' 버튼이 보이지 않는다.
  • bbb@naver.com은 test1의 수정 버튼이 보이지 않고, 2, 3는 보인다.

 

 

다음은 로그인을 하지 않은 상황의 결과 화면이다.

  • anonumousUser이고, 수정버튼이 보이지 않는다.
  • ※ 마이페이지 저장 버튼을 누를 시엔 로그인 화면으로 이동한다.

 

 

다음은 aaa@naver.com으로 로그인한 결과이다.

  • test1 게시물의 화면이다.
  • 수정 버튼이 잘 보인다.

 

  • test2, test3 게시물의 화면이다.
  • 수정 버튼이 보이지 않는다.

 

 

 

다음은 bbb@naver.com으로 로그인해보자.

  • test1 게시물엔 수정 버튼이 보이지 않는다.

 

 

  • test2, test3 게시물엔 수정 버튼이 보인다.

 

 

 

의도한 결과가 나왔다.

 

 

 

- 끝 -