로그인 템플릿을 먼저 작성해준다.
<html layout:decorate="~{layout}">
<div layout:fragment="content" class="container my-3">
<form th:action="@{/member/login}" method="post">
<div th:if="${param.error}">
<div class="alert alert-danger">
사용자ID 또는 비밀번호를 확인해 주세요.
</div>
</div>
<div class="mb-3">
<label for="username" class="form-label">사용자ID</label>
<input type="text" name="username" id="username" class="form-control">
</div>
<div class="mb-3">
<label for="password" class="form-label">비밀번호</label>
<input type="password" name="password" id="password" class="form-control">
</div>
<button type="submit" class="btn btn-primary">로그인</button>
</form>
</div>
</html>
먼저 권한생성을 위해 MemberRole이라는 enum자료형을 생성해준다.
@Getter
public enum MemberRole {
Admin("admin"),Member("member");
private String value;
MemberRole(String value){
this.value=value;
}
}
스프링 시큐리티가 로그인시 사용할 기능을 작성해준다.
package com.example.quenswer.member;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class MemberSecurityService implements UserDetailsService { #UserDetailsService는 loadUserByUsername 메서드를 구현하도록 강제하는 인터페이스
private final MemberRepository memberRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { #loadUserByUsername 메서드는 사용자명(username)으로 스프링 시큐리티의 사용자(Member) 객체를 조회하여 리턴하는 메서드
Optional<Member> om=memberRepository.findByUserId(username);
if (om.isEmpty()){
throw new UsernameNotFoundException("사용자를 찾을수 없습니다.");
}
Member member=om.get();
List<GrantedAuthority> authorities=new ArrayList<>();
if ("admin".equals(username)){
authorities.add(new SimpleGrantedAuthority(MemberRole.Admin.getValue()));
}else {
authorities.add(new SimpleGrantedAuthority(MemberRole.Member.getValue()));
}
return new User(member.getUserId(),member.getPassword(),authorities);
}
}
UserDetailsService는 spring security에서 유저정보를 가져오는 인터페이스로, UserDetails타입의 loadUserByUsername메서드를 구현해야한다.
loadUserByUsername 메서드는 username으로 Member 객체를 조회하고, 만약 사용자명에 해당하는 데이터가 없을 경우에는 UsernameNotFoundException을 발생시킨다.
그리고 사용자명이 'admin'인 경우에는 ADMIN 권한(ROLE_ADMIN)을 부여하고 그 이외의 경우에는 USER 권한(ROLE_USER)을 부여했다.User 생성자에는 사용자명, 비밀번호, 권한 리스트가 전달된다.
header.heml도 수정해줍니다.
<header class="p-3 text-bg-dark" th:fragment="headerFragment" xmlns:sec="http://www.w3.org/1999/xhtml">
<div class="container">
<div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
<a href="/" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none">
<svg class="bi me-2" width="40" height="32" role="img" aria-label="Bootstrap">
<use xlink:href="#bootstrap"></use>
</svg>
</a>
<ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
<li><a href="/question/" class="nav-link px-2 text-white">Home</a></li>
<li><a href="#" class="nav-link px-2 text-white">Features</a></li>
<li><a href="#" class="nav-link px-2 text-white">Pricing</a></li>
<li><a href="#" class="nav-link px-2 text-white">FAQs</a></li>
<li><a href="#" class="nav-link px-2 text-white">About</a></li>
</ul>
<form class="col-12 col-lg-auto mb-3 mb-lg-0 me-lg-3" role="search">
<input type="search" class="form-control form-control-dark text-bg-dark" placeholder="Search..."
aria-label="Search">
</form>
<div class="text-end">
<button type="button" class="btn btn-outline-light me-2" sec:authorize="isAnonymous()" th:onclick="|location.href='@{/member/login}'|">Login</button> #sec:authorize="isAnonymous()": 로그인되지 않은 경우에 해당 요소(로그인 링크)가 표시
<button type="button" class="btn btn-outline-light me-2" sec:authorize="isAuthenticated()" th:onclick="|location.href='@{/member/logout}'|">Logout</button> #sec:authorize="isAuthenticated()": 로그인된 경우에 해당 요소(로그아웃 링크)가 표시
<button type="button" class="btn btn-warning" th:onclick="|location.href='@{/member/signup}'|">Sign-up</button>
</div>
</div>
</div>
</header>
로그인을 하지않은 상태(로그인표시)
로그인을 성공한 상태(로그아웃버튼 활성화)
'웹개발' 카테고리의 다른 글
quenswer(프로젝트)-QuestionDetails (0) | 2024.02.26 |
---|---|
quenswer(프로젝트)-spring security(회원가입) (0) | 2024.02.04 |
quenswer(프로젝트)-QuestionList (0) | 2024.01.08 |
quenswer(프로젝트)-Junit Test(Answer) (0) | 2023.12.29 |
quenswer(프로젝트)-Junit Test(Question) (0) | 2023.12.29 |