이제 인증기능을 뷰에 적용시켜보자.
로그인 로그아웃 버튼 생성
<div class="text-end">
<span id="username" class="text-white me-2">username</span>
<a role="button" id="login" class="btn btn-outline-light me-2">Login</a>
<a role="button" id="logout" class="btn btn-outline-light me-2"></a>
</div>
header.th.sml
<?xml version="1.0"?>
<thlogic xmlns:th="http://www.thymeleaf.org">
<attr sel="#home" th:href="@{/}"/>
<attr sel="#hashtag" th:href="@{/articles/search-hashtag}"/>
<attr sel="#username" sec:authorize="isAuthenticated()" sec:authentication="name"/>
<attr sel="#login" sec:authorize="!isAuthenticated()" th:href="@{/login}"/>
<attr sel="#logout" sec:authorize="isAuthenticated()" th:href="@{/logout}"/>
</thlogic>
인증 여부에 따라서 login 버튼, 혹은 logout 버튼을 보여준다.
로그인을 들어가서 유저 계정과 비밀번호를 입력하고 들어가면
PasswordEncoder에 id가 null로 나타났다.
PasswordEncoder는 PasswaordEncoderFactories에서 createDelegatingPasswordEncoder를 사용하는데, 패스워드 데이터 앞머리에 내용을 붙여주지 않으면 인식을 얘가 인식을 하지 못한다. 앞머리에 추가하는 내용은 바로 암호화 규칙으로 여러가지 방식으로 선택이 가능하지만, 지금은 테스트 단계이니 만큼 {noop}을 붙여서 비밀번호가 그대로 보여지게 설정한다. 물론 암호화 규칙을 적용하는것도 좋지만, 비밀번호를 어떤 값으로 지정했는지를 바로 볼수 없는 것이 불편하기 때문이다.
data.sql 파일에서 유저 테스트 데이터의 비밀번호 값의 앞에다가 {noop}를 추가해준다.
이렇게 해주면 로그인이 되서 게시글 페이지로 들어가게 된다.
로그인이 되어있는 경우에만 글을 쓸수 있도록 게시판 페이지의 글쓰기 버튼을 인증 여부에 따라 나타나거나 사라지게 설정했다.
index.th.xml
<attr sel="#write-article" sec:authorize="isAuthenticated()" th:href="@{/articles/form}"></attr>
게시글 페이지의 수정과 삭제버튼은 게시글 작성자와 인증 사용자가 같은 경우에만 나타나게 설정해서 다른 사람들이 수정,삭제를 할수 없게 설정했다.
게시글 페이지의 댓글에 생성된 삭제버튼또한 인증 사용자가 댓글 작성자와 같은 경우에만 삭제를 할수 있어야한다. 따라서 다른 사용자의 댓글에는 삭제라는 버튼이 나타나지 않게 수정했다.
detail.th.xml
<attr sel="#article-buttons" th:if="${#authorization.expression('isAuthenticated()')} and *{userId} == ${#authentication.name}">
<attr sel="#delete-article-form" th:action="'/articles/' + *{id} + '/delete'" th:method="post">
<attr sel="#update-article" th:href="'/articles/' + *{id} + '/form'" />
</attr>
...
<attr sel="div/small/time" th:datetime="${articleComment.createdAt}"
th:text="${#temporals.format(articleComment.createdAt, 'yyyy-MM-dd HH:mm:ss')}"/>
<attr sel="div/p" th:text="${articleComment.content}"/>
<attr sel="button" th:if="${#authorization.expression('isAuthenticated()')} and ${articleComment.userId} == ${#authentication.name}" />
이렇게 뷰까지 만들어서 다 된줄 알았는데 자세히 테스트 해보니 수정 기능이 제대로 동작하지 않았다.
테스트도 전부 통과를 해서 보안 이유로 방어되어서 수정되지 않은 것인줄 알았는데, userAccount 도메인에서 equals()에 오류가 생긴것을 발견했다. userId를 비교하는 내용에서 that.id 같은 표현이 본래의 역할을 수행하고 있지 않아서 userId비교가 되지 않아서 수정되지 않은 것이다. 따라서 제대로 getter
를 사용해서 값을 불러오게 수정했고 이름또한 that
으로 통일 시켰다.
article
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Article that) ) return false;
return id != null && id.equals(that.getId());
}
articleComment
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ArticleComment that)) return false;
return id != null && id.equals(that.getId());
}
userAccount
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof UserAccount that)) return false;
return userId != null && userId.equals(that.getUserId());
}
이제 완벽하게 게시글이 동작한다.