Security 권한에 따른 페이지 접속
앞의 Security 속성 설정에 이어, 회원에게 부여된 권한에 따른 페이지 인가를 설정해주려고 한다.
01) 회원 객체와 권한 enum 생성
📑ClubMember
package com.example.springsecurity.entity;
import lombok.*;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import java.util.HashSet;
import java.util.Set;
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Builder
@ToString
public class ClubMember extends BaseEntity {
@Id
private String email;
private String password;
private String name;
private Boolean fromSocial;
// 권한
@ElementCollection(fetch = FetchType.LAZY)
@Builder.Default
private Set<ClubMemberRole> roleSet = new HashSet<>();
public void addMemberRole(ClubMemberRole clubMemberRole){
roleSet.add(clubMemberRole);
}
}
📑ClubMemberRole ( enum )
package com.example.springsecurity.entity;
public enum ClubMemberRole {
USER,MANAGER,ADMIN
}
[ Spring Security 구조 ]
02) Security를 위한 권한 정보(User)를 가지고 있는 회원 DTO 생성
User
UserDetails (인터페이스) 를 구현한 객체이다.
추가적으로 필요한 기능이 없다면 User 클래스를 사용하는 것이 더 수월하다.
UserDetails (인터페이스)
- getAuthorities() : 사용자가 가지는 권한 정보
- getPassword() : 인증을 마무리하기 위한 패스워드 정보
- getUsername() : 인증에 필요한 아이디와 같은 정보
- 계정 만료 여부
- 계정 잠김여부
📑ClubAuthMemberDTO
1. User 객체를 상속 받는다.
public class ClubAuthMemberDTO extends User {
...
}
2. 생성자 메서드에서 권한정보( 슈퍼클래스 : User ) 에 사용자의 정보를 넘겨준다.
- GrantedAuthority : 권한정보를 부여받은 임의(?)의 객체를 받아서 권한정보( 슈퍼클래스 : User ) 에 값을 넘겨준다.
Collection < ? extends GrantedAuthority > authorities
3. 이외에 ' 📑ClubMember ' 객체에서 필요했던 필드를 객체 생성 시 함께 입력될 수 있도록 추가해준다.
package com.example.springsecurity.security.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
@Getter
@Setter
@ToString
@Log4j2
public class ClubAuthMemberDTO extends User {
private String email; //id
private String name;
private Boolean fromSocial;
public ClubAuthMemberDTO(String username,
String password,
Boolean fromSocial,
Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
this.email = username;
this.fromSocial = fromSocial;
}
}
03) Security 회원 처리를 하는 UserDetailsService
UserDetailsService
사용자의 정보를 가져오는 핵심적인 역할을 하는 인터페이스이다.
스프링 시큐리티의 구조에서 인증을 담당하는 AuthenticationManager는
내부적으로 UserDetailsService를 호출해서 사용자의 정보를 가져온다.
📑ClubUserDetailService
1. UserDetailsService인터페이스를 상속받는 Service 클래스를생성
- @Service 어노테이션을 사용하여 자동으로 등록될 수 있도록 스프링 빈으로 처리한다.
@Service
public class ClubUserDetailService implements UserDetailsService {
...
}
2. 일치하는 User가 존재하는지 검색
- 싱글톤패턴으로 레파지토리를 선언하여 사용한다.
- 사용자가 없을 경우 UsernameNotFoundException으로 처리
- 사용자가 있을경우 권한을 가진 회원 DTO를 생성하여 리턴 해준다.
package com.example.springsecurity.security.service;
import com.example.springsecurity.entity.ClubMember;
import com.example.springsecurity.repository.ClubMemberRepository;
import com.example.springsecurity.security.dto.ClubAuthMemberDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.Optional;
import java.util.stream.Collectors;
@Log4j2
@Service
@RequiredArgsConstructor
public class ClubUserDetailService implements UserDetailsService {
private final ClubMemberRepository clubMemberRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("ClubUserDetailService load username : {}", username);
Optional<ClubMember> result = clubMemberRepository.findByEmail(username, false);
// 동일 이메일이 없을 경우
if (!result.isPresent()){
throw new UsernameNotFoundException("Check Email or Social");
}
log.info("----------------------------------");
// 존재 할 경우
ClubMember clubMember = result.get();
log.info(clubMember);
ClubAuthMemberDTO clubAuthMemberDTO = new ClubAuthMemberDTO(
clubMember.getEmail(),
clubMember.getPassword(),
clubMember.getFromSocial(),
clubMember.getRoleSet().stream().map(role->
new SimpleGrantedAuthority("ROLE_"+role.name())).collect(Collectors.toSet())
);
clubAuthMemberDTO.setName(clubMember.getName());
clubAuthMemberDTO.setFromSocial(clubMember.getFromSocial());
return clubAuthMemberDTO;
}
}
04) HTML 마크업
📑Member.html
1. <html> 태그 속성 추가
- xmlns:th="http://www.thymeleaf.org"
- xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
2. 출력하고 싶은 속성값 추가
<div sec:authentication="속성값"></div>
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>member</title>
</head>
<body>
<h1>member page</h1>
<div sec:authorize="isAuthenticated()">
only Authenticated user can see this Test
</div>
Authenticated username :
<div sec:authentication="name"></div>
Authenticated user roles :
<div sec:authentication="principal.authorities"></div>
</body>
</html>
'BackEnd > Security · JPA' 카테고리의 다른 글
[ Security ] 04. 시큐리티 - 자동 로그인 설정 / Remember Me (1) | 2023.06.01 |
---|---|
[ Security ] 03. 시큐리티 소셜 로그인 처리 - Google oauth2 (0) | 2023.05.24 |
[ Security ] 01. 시큐리티 사용하기 - WebSecurityConfigurerAdapter 권한 설정 (스프링 부트 버전 2.7.0이전) (0) | 2023.05.23 |
[ Security ] 01. 시큐리티 사용하기 - 설정 파일 (0) | 2023.05.03 |
[ JPA ] 동적 쿼리 처리를 해주는 Querydsl 사용해보기 (1) | 2023.04.16 |