minlog
article thumbnail

Security 권한에 따른 페이지 접속

 

앞의 Security 속성 설정에 이어, 회원에게 부여된 권한에 따른 페이지 인가를 설정해주려고 한다.

 

 

[ Security ] 시큐리티 사용하기 - 01. 설정 파일

시큐리티 설정 파일 시큐리티와 관련된 모든 설정들을 관리하는 config 클래스 이다. 스프링 부트 버전 2.7.0 이전에는 ' WebSecurityConfigurerAdapter ' 를 상속받아서 사용해야하며, 이후 부터는 사용되지

jimin-log.tistory.com


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>

 

 

profile

minlog

@jimin-log

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!