3. ํ๋ก์ ํธ๋ฅผ ์ํ JPA ์ฒ๋ฆฌ
4. ์ํ๋ฆฌํฐ๋ฅผ ์ํ UserDetailsService
5. Controller์์ ์ฌ์ฉ์ ์ ๋ณด ์ถ๋ ฅํ๊ธฐ
3. ํ๋ก์ ํธ๋ฅผ ์ํ JPA ์ฒ๋ฆฌ
ClubMember: ์ํฐํฐ ํด๋์ค
ClubMemberRole: ์ํฐํฐ enum ํด๋์ค
ClubMemberRepository: repository ์ธํฐํ์ด์ค
ClubAuthMemberDTO: DTO ํด๋์ค(์คํ๋ง ์ํ๋ฆฌํฐ์ User ํด๋์ค๋ฅผ ์์ํจ)
ClubUserDetailsService: service ํด๋์ค, AuthenticationManager๊ฐ ๋ด๋ถ์ ์ผ๋ก ํธ์ถํ์ฌ ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๋ ํด๋์ค (UserDetailsService ์ธํฐํ์ด์ค ์์ํจ)
User: ์คํ๋ง ์ํ๋ฆฌํฐ์์ ์ฌ์ฉํ๋ ํ์, ๊ณ์ ์ ๋ํ ์ฉ์ด
username: ํ์์ ๊ตฌ๋ณํ ์ ์๋ ์๋ณ ๋ฐ์ดํฐ (์ผ๋ฐ์ ์ธ id์ ์ ์ฌํ ๊ธฐ๋ฅ)
ClubMember
entity ํจํค์ง ๋ด์ ํด๋์ค
addMemberRole ๋ฉ์๋๋ก ์ฌ์ฉ์์ ์ญํ ์ถ๊ฐ ๊ฐ๋ฅ
package org.zerock.club.entity;
import lombok.*;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import java.util.Set;
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
public class ClubMember extends BaseEntity {
@Id
private String email;
private String password;
private String name;
private boolean fromSocial;
@ElementCollection(fetch = FetchType.LAZY)
private Set<ClubMemberRole> roleSet;
public void addMemberRole(ClubMemberRole clubMemberRole){
roleSet.add(clubMemberRole);
}
}
ClubMemberRole
entity ํจํค์ง ๋ด์ enum ํด๋์ค
์ฌ์ฉ์์ Role์ ์ ์ํด๋
package org.zerock.club.entity;
public enum ClubMemberRole {
USER,MANAGER,ADMIN
}
ClubMemberRepository
package org.zerock.club.repository;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.zerock.club.entity.ClubMember;
import java.util.Optional;
public interface ClubMemberRepository extends JpaRepository<ClubMember, String> {
@EntityGraph(attributePaths = {"roleSet"}, type = EntityGraph.EntityGraphType.LOAD)
@Query("select m from ClubMember m where m.fromSocial = :social and m.email =:email")
Optional<ClubMember> findByEmail(String email, boolean social);
}
์ด๋ฉ์ผ, ์์ ๋ก ์ถ๊ฐ๋ ํ์ ์ฌ๋ถ ์ ๋ ฅ๋ฐ์ ์ฌ์ฉ์ ๊ฒ์
@EntityGraph: left outer join์ผ๋ก ClubMemberRole๋ ๋ก๋ฉ๋ ์ ์๋๋ก ํจ
4. ์ํ๋ฆฌํฐ๋ฅผ ์ํ UserDetailsService
ClubAuthMemberDTO
UserDetails ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ User ํด๋์ค๋ฅผ ์์
-> DTO์ ๊ฐ์ ๊ฐ๋ ์ผ๋ก ๋ณ๋ ํด๋์ค(User)๋ฅผ ๊ตฌ์ฑํ๊ณ ํ์ฉํ๋ ๋ฐฉ์
UserDetails ํ์
- getAuthorities() : ์ฌ์ฉ์๊ฐ ๊ฐ์ง๋ ๊ถํ ์ ๋ณด ํ๋
- getPassword(): ์ธ์ฆ์ ๋ง๋ฌด๋ฆฌํ๊ธฐ ์ํ ํจ์ค์๋ ์ ๋ณด ํ๋
- getUsername(): ์ธ์ฆ์ ํ์ํ ์์ด๋ ๊ฐ์ ์ ๋ณด ํ๋
- ๊ณ์ ๋ง๋ฃ/์ ๊น ์ฌ๋ถ ํ์ธ
package org.zerock.club.security.dto;
import lombok.Data;
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;
@Log4j2
@Getter
@Setter
@ToString
public class ClubAuthMemberDTO extends User {
private String email;
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;
}
}
super(...): ๋ถ๋ชจ ํด๋์ค์ธ User ํด๋์ค์ ์ฌ์ฉ์ ์ ์ ์์ฑ์๋ฅผ ํธ์ถ
password๋ ๋ถ๋ชจ ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ๋ฉค๋ฒ ๋ณ์๋ก ์ ์ธํ์ง ์์
ClubUserDetailsService
UserDetailsService ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ํด๋์ค
package org.zerock.club.security.service;
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 org.zerock.club.entity.ClubMember;
import org.zerock.club.repository.ClubMemberRepository;
import org.zerock.club.security.dto.ClubAuthMemberDTO;
import java.util.Optional;
import java.util.stream.Collectors;
@Log4j2
@Service
@RequiredArgsConstructor
public class ClubUserDetailsService implements UserDetailsService {
private final ClubMemberRepository clubMemberRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("ClubUserDetailsService loadUserByUsername " + username);
Optional<ClubMember> result = clubMemberRepository.findByEmail(username, false);
if(result.isEmpty()){
throw new UsernameNotFoundException("Check User Email or from Social ");
}
ClubMember clubMember = result.get();
log.info("-----------------------------");
log.info(clubMember);
ClubAuthMemberDTO clubAuthMember = new ClubAuthMemberDTO(
clubMember.getEmail(),
clubMember.getPassword(),
clubMember.isFromSocial(),
clubMember.getRoleSet().stream()
.map(role -> new SimpleGrantedAuthority("ROLE_"+role.name()))
.collect(Collectors.toSet())
);
clubAuthMember.setName(clubMember.getName());
clubAuthMember.setFromSocial(clubMember.isFromSocial());
return clubAuthMember;
}
}
- ClubMemberRepository๋ฅผ ์ฃผ์ ๋ฐ์ ์ ์๋ ๊ตฌ์กฐ๋ก ๋ณ๊ฒฝ + @RequiredArgsConstructor ์ฒ๋ฆฌ
- ClubMemberRepository์ findByEmail ๋ฉ์๋ ํธ์ถ
- ClubMember๋ฅผ UserDetailsํ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํด ClubAuthMemberDTOํ์ ์ผ๋ก ๋ณํ
- ClubMemberRole์ SimpleGrantedAuthority๋ก ๋ณํ ์ฒ๋ฆฌ
5. Controller์์ ์ฌ์ฉ์ ์ ๋ณด ์ถ๋ ฅํ๊ธฐ
SampleController
๋ก๊ทธ์ธ๋ ์ฌ์ฉ์ ์ ๋ณด ํ์ธํ๋ ๋ฐฉ๋ฒ
1) SecurityContextHolder ๊ฐ์ฒด ์ฌ์ฉ
2) ์ง์ ํ๋ผ๋ฏธํฐ์ ์ด๋ ธํ ์ด์ ์ฌ์ฉ
SampleController ๋ด์ exMember ๋ฉ์๋
AuthenticationPrincipal ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉ
@GetMapping("/member")
public void exMember(@AuthenticationPrincipal ClubAuthMemberDTO clubAuthMember){
log.info("exMember..........");
log.info("-------------------------------");
log.info(clubAuthMember);
}
๋๊ธ