게시판에 글 등록할 때 ‘비밀글 여부’에 체크박스 활성화를 시킨 경우 Spring Security에서 ROLE 확인 후 서버 내부에서 해당 게시글 표출 안되게 끔 하는 작업이다.
아무래도 페이지네이션이랑 같이 작업해야하는 부분이다보니 처음에 화면 단에서 Spring Security 써서 비밀 글 표출 안되게 하는 방법을 적용해봤는데 그럼 화면 단에서 페이지네이션도 해당 부분을 처리해야하는거라 그럴바엔 서버에서 처리하자.. 이렇게 생각하게 되었다.
사실 삽질을 좀 하긴 했는데(;;) 다시 한번 리마인드 해보니 굉장히 쉬운 작업이였다..
일단 Controller 단에서 아래 부분을 호출해서 로그를 찍어보자.
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// MyUserDetails myUserDetails = (MyUserDetails) authentication.getPrincipal();
// 비회원 권한 - ROLE_ANONYMOUS
authentication = AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=5FCA5BBA31A0814522894CB8A314D457], Granted Authorities=[ROLE_ANONYMOUS]]
// ADMIN 계정 권한 - ROLE_ADMIN
authentication = UsernamePasswordAuthenticationToken [Principal=com.project.homepage.security.MyUserDetails@2bfc4e6f, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=5FCA5BBA31A0814522894CB8A314D457], Granted Authorities=[ROLE_ADMIN]]
참고로 ADMIN 권한은 DB에 있는 데이터다.
로그인에 성공할 경우 해당 회원이 가진 권한을 저장하게 된다.
이전에 생각해뒀던 바보같은 로직은 아래와 같다.
- 비공개 여부 컬럼을 조건문으로 걸지 않은 데이터를 뽑아온다.
- 루프를 돌려 권한과 비공개 여부 컬럼 확인 후 일치하면 remove 시킨다.
그리고 수정한 로직은 아래와 같다.
- mapper 호출 시 if문으로 권한이 익명 사용자일 경우 비밀 글을 걸러낸다.
@GetMapping("/list")
public String main(@RequestParam(name = "page", required = false, defaultValue = "1") int page, @RequestParam Map<String, Object> requestMap, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String role = getRole(authentication.getAuthorities());
String code = (String) requestMap.get("code");
String title = getTitle(code);
String url = "board/list";
int amount = 10;
int offset = (page == 1 ? 0 : (page - 1) * amount);
requestMap.put("offset" , offset);
requestMap.put("amount" , amount);
requestMap.put("role" , role);
List<Map<String, Object>> boardGet = service.boardGet(requestMap);
int boardGetCnt = service.boardGetCnt(requestMap);
Pagination pagination = new Pagination(page, amount, boardGetCnt);
model.addAttribute(Const.DATA , boardGet);
model.addAttribute(Const.ARTICLE_TITLE , title);
model.addAttribute(Const.PAGINATION , pagination);
model.addAttribute(Const.SEARCH_DATA , requestMap);
return url;
}
<select id="boardGet" parameterType="map" resultType="map">
SELECT ROW_NUMBER() OVER(ORDER BY A.IBOARD DESC) ROWNUMBER, A.IBOARD, A.ICODE, A.TITLE, (SELECT NAME FROM tbl_code WHERE ICODE = A.GENRE) GENRE, IFNULL(C.NAME, '') TUMBNAIL, IFNULL(A.YOUTUBE_ID, '') YOUTUBE_ID, A.CREATED_AT, A.SEC_YN
FROM tbl_board A
INNER JOIN tbl_code B
ON A.ICODE = B.ICODE
LEFT JOIN tbl_thumbnail C
ON A.IBOARD = C.IBOARD
WHERE A.DEL_YN = 'N' AND A.ICODE = #{code}
<if test="search != null and search != ''">
AND A.TITLE LIKE CONCAT('%', #{search}, '%')
</if>
<if test="role == 'ROLE_ANONYMOUS'">
AND SEC_YN = 'N'
</if>
ORDER BY A.IBOARD DESC
LIMIT #{offset}, #{amount}
</select>
<select id="boardGetCnt" parameterType="map" resultType="int">
SELECT COUNT(*)
FROM tbl_board
WHERE DEL_YN = 'N' AND ICODE = #{code}
<if test="search != null and search != ''">
AND A.TITLE LIKE CONCAT('%', #{search}, '%')
</if>
<if test="role == 'ROLE_ANONYMOUS'">
AND SEC_YN = 'N'
</if>
ORDER BY CREATED_AT DESC
</select>
테스트해보자.
SELECT sec_yn AS '비공개 여부', title AS '제목' FROM tbl_board WHERE icode = 'B003' AND sec_yn = 'Y';
로그인 전 익명 사용자로 들어올 경우엔 비밀글이 보이지 않는다.
ADMIN 권한 계정으로 로그인을 할 경우엔 비공개 글이 표출된다.
+
try {
Map<String, Object> boardSelect = service.boardSelect(requestMap);
String code = (String) boardSelect.get("icode");
String secYn = (String) boardSelect.get("sec_yn");
String role = getRole();
requestMap.put("role", role);
if(secYn.equals("Y") && role.equals(Const.ROLE_ANONYMOUS)) {
throw new AccessDeniedException("권한이 없습니다.");
}
List<Map<String, Object>> prevPost = service.prevPostGet(requestMap);
List<Map<String, Object>> nextPost = service.nextPostGet(requestMap);
String title = getTitle(code);
boardSelect.put("article_title" , title);
boardSelect.put("contents" , commonmarkUtil.markdown((String) boardSelect.get("contents")));
model.addAttribute(Const.PREV_POST , prevPost);
model.addAttribute(Const.NEXT_POST , nextPost);
model.addAttribute(Const.DATA , boardSelect);
return "board/read";
} catch(AccessDeniedException e) {
return "access-denied";
}
익명 사용자가 주소창에서 비공개 글 상세보기 url을 호출할 경우에는 AccessDeniedException 예외를 던지고 해당 예외를 잡은 catch문에서 access-denied 페이지로 이동하게 끔만 해놨다. 바로 예외를 던져버리기 때문에 데이터를 받아 보내진 않지만 해당 방법은 좋은 방법은 아닌 것 같고 다른 방법을 찾아봐야 할 듯 하다. 레퍼런스 안찾아봐서 아직 잘 모름..
'Spring' 카테고리의 다른 글
[Spring] Swagger UI 초기 세팅 (0) | 2025.01.26 |
---|---|
[Spring] Rest API ExceptionHandler (0) | 2025.01.19 |
[Spring] CustomExceptionHanlder (1) | 2024.11.29 |
[Spring] 검색 결과 미리보기 (0) | 2024.11.17 |
[Spring] RSS(XML) Parsing (0) | 2024.09.21 |