Spring Springセキュリティを使用したログイン処理-(4)


投影処理JPA


  • もちろん、スプリングセキュリティをプロジェクトに適用するには、データベース関連の処理が必要です.

  • 例は、IDではなく最近ソーシャルログインで多くの電子メールをIDとして整理することによってメンバーを処理する.

  • 会員情報は次のとおりです.
    -電子メール(ID)
    -パスワード
    -名前(ニックネーム)
    -SNSに加入しているかどうか(SNSを通じて会員に加入している場合)
    -その他(登録日/変更日)

  • 通常のメンバー管理とは異なり、ロールに対する処理です.次の例では、「権限」(ClubMemberRole)を使用します.
    -USER:一般会員
    -マネージャ:中間管理メンバー
    -ADMIN:総経理

  • 通常の設計では、1つのメンバーの権限しかありませんが、プロジェクトを構成するには、1つのクラブのメンバーに複数の権限が必要です.

  • ClubMemberとClubMemberRoleの関係は1:Nですが、実際にはClubMemberRole自体は重要な役割を果たすことはできません.したがって、PKを必要とせずに、@ElementCollectionを使用して個々のエンティティではなく組織します.

  • プロジェクトでエンティティパッケージを構成し、BaseEntityとClubMemberというクラスを作成します.



  • EntityパッケージにClubMemberRoleというenumタイプを作成し、指定した権限を指定します.
  • public enum ClubMemberRole {
        USER, MANAGER, ADMIN
    }
     //이 어노테이션은 지정된 속성이 컬렉션을 사용할 것이라는 의미이다.
        //Entity가 아닌 단순한 형태의 객체 집합을 정의하고 관리하는 방법이다.
        //한 테이블에서 연관된 다른 테이블에 대한 정보를 다루는데 One-To-Many관계를 다룬다
    
        //Fetch Type은 크게 Eager와 Lazy 두 가지의 전략이 있습니다. Eager 전략은 엔티티를 조회할 때,
        // 연관 관계에 있는 엔티티도 함께 가져오고,
        // 반대로 Lazy 전략은 연관 관계 엔티티를 참조할 때 그때서야
        // 가져오게 됩니다.
        @ElementCollection(fetch= FetchType.LAZY)
        @Builder.Default
        private Set<ClubMemberRole> roleSet=new HashSet<>();
    
        public void addMemberRole(ClubMemberRole clubMemberRole){
            roleSet.add(clubMemberRole);
        }
    }
  • クラブメンバーのデータでは、パスワードを暗号化してデータを追加する必要があるため、テストコードを作成して100アカウントを作成します.
  • リポジトリパッケージを追加し、ClubMember Repositoryを作成します.

  • 作成
  • テストコード
  • import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.zerock.club.entity.ClubMember;
    import org.zerock.club.entity.ClubMemberRole;
    
    import java.util.stream.IntStream;
    
    @SpringBootTest
    public class ClubMemberRepositoryTests {
        @Autowired
        private ClubMemberRepository clubMemberRepository;
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Test
        @DisplayName("100더미생성")
        void insertDummies(){
            //1-80까지는 USER만 지정,
            //81-90까지는 USER,MANAGER,
            ///91-100까지는 USER,MANAGER,ADMIN
            IntStream.rangeClosed(1,100).forEach(i->{
                ClubMember clubMember = ClubMember.builder()
                        .email("user"+i+"@naver.com")
                        .name("사용자"+i)
                        .fromSocial(false)
                        .password(passwordEncoder.encode("1111"))
                        .build();
                //default role
                clubMember.addMemberRole(ClubMemberRole.USER);
                
                if(i>80){
                    clubMember.addMemberRole(ClubMemberRole.MANAGER);
                }
                if(i>90){
                    clubMember.addMemberRole(ClubMemberRole.ADMIN);
                }
                clubMemberRepository.save(clubMember);
    
            });
        }
    }
    

    メンバー・データ・クエリーのテスト

  • は、通常のログインユーザに追加された後のソーシャルログインユーザを区別するために、ClubMember Repositoryとは独立した方法と見なされる.
  • import java.util.Optional;
    
    public interface ClubMemberRepository extends JpaRepository<ClubMember,String> {
    
        //@EntityGraph는 연관 엔티티의 특정한 속성을 같이 로딩하도록 표시합니다.
        //기본적으로 JPA를 이용하는 경우에는 연관 관계의 FATCH 속성값은 LAZY로 지정합니다.
        //attributePaths : 로딩 설정을 변경하고 싶은 속성의 이름을 배열로 명시합니다.
        //type : @EntityGraph를 어떤 방식으로 적용할 것인지를 설정
        //FATCH 속성값은 attributePaths에 명시한 속성은 EAGER로 처리하고 나머지는 LAZY로 처리합니다.
        //LOAD 속성값은 attributePaths에 명시한 속성은 EAGER로 처리하고 나머지는 엔티티 클래스에 명시되거나 기본 방식으로 처리합니다.
        //EntityGraph를 이용해서 'left outer join'으로 ClubMemberRole이 처리될수 있도록 합니다.
        
        @EntityGraph(attributePaths = {"roleSet"},type = EntityGraph.EntityGraphType.LOAD)
        @Query("select m from ClubMember m where m.fromSocial = :social and m.email =:email")
       Optional<ClubMember> findByEmail(@Param("email") String email, @Param("social") boolean social);
        //Optional은 non-null 값을 가지고 있거나 안 가지고 있을 수 있는 컨테이너 오브젝트이다
        // 값이 존재하면 isPresent()는 true를 반환하고
        //값이 존재하지 않으면 false를 반환한다. 객체를 감싸고 그 안에 값이 있는지 없는지 유무를 판별하기 좋다.
    }
    
    ```java
    @Test
        @DisplayName("회원데이터 조회")
        public void testRead(){
    
            Optional<ClubMember> result = clubMemberRepository.findByEmail("[email protected]", false);
    
            if(result.isPresent()){
                System.out.println(result.get());
            }
        }
    ClubMember(email=user28@naver.com, password=$2a$10$KIxhZJYQ8qA8Dl1ZD7fEs.SZMvwgSjG7Hs7oOoGPs5SCIbZXwYRwO, name=사용자28, fromSocial=false, roleSet=[USER])