본문 바로가기
공부/프로그래밍

[SpringBoot] (Spring Security) 로그인 시 추가정보 User 에 담기

by demonic_ 2018. 7. 5.
반응형

해당기능을 사용할 시 외부로그인 연동(네이버나 페이스북 로그인 등)시 세션처리에 문제를 겪을 수 있어 추천드리지 않습니다.



스프링 시큐리티에서는 로그인 하면 org.springframework.security.core.userdetails.User 클래스로 리턴하게 됩니다. 그리고 UserDetailService를 이용해 사용자 정보를 읽어냅니다.

문제는 User 클래스는 username, password, authorities 등의 기본정보만 들어있습니다. 그래서 여기에 이메일이나 전화번호 등 추가정보를 넣어주려면 클래스를 새로 만들어주어야 합니다.


설정 순서는 다음과 같습니다.

1) User 를 커스텀한 UserCustom 클래스를 작성.(Lombok 사용)

2) UserDetailsService 인터페이스를 구현하는 클래스를 작성.


여기서는 user_email, user_name 을 추가등록 하겠습니다.



1) UserCustom 클래스 작성(lombok 사용)

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;

// lombok 사용
// Security 에서 사용되는 User 에서 파라미터를 추가함.
//@Data         // constructor 도중 에러가 발생하므로 사용하지 않음
@Getter @Setter @ToString
public class UserCustom extends User {
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

    // 유저의 정보를 더 추가하고 싶다면 이곳과, 아래의 생성자 파라미터를 조절해야 한다.
    private String user_email;
    private String user_name;

    public UserCustom(String username, String password
            , boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked
            , Collection authorities
            , String user_email, String user_name) {
        super(username, password
                , enabled, accountNonExpired, credentialsNonExpired, accountNonLocked
                , authorities);
        this.user_email = user_email;
        this.user_name = user_name;
    }
}



2) UserDetailsService 인터페이스를 구현한 클래스 생성

@Service
public class CustomUserDetailService implements UserDetailsService {
    // DB 를 통해 유저정보를 가져오기 위해 주입된 매퍼
    @Autowired
    MemberMapper memberMapper;


    // 시큐리티의 내용 외 파라미터를 추가하고 싶을 때, 아래 사용
    //  제약조건: Controller 에서 Auth를 점검할 때, UserCustom 으로 받아야 함.
    //  예) (변경 전) @AuthenticationPrincipal User user => (변경 후) @AuthenticationPrincipal UserCustom user
    boolean enabled = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;

		@Override
    public UserDetails loadUserByUsername(String user_email) throws UsernameNotFoundException {
    		// 로그인 시도하려는 유저정보 조회
        MemberDTO memberDTO = memberMapper.chkLogin(user_email);

        // 조회가 되지않는 고객은 에러발생.
        if(memberDTO == null){
            throw new UsernameNotFoundException(user_email);
        }

        // 조회한 정보를 userCustom에 담는다.
        // 만약 파라미터를 추가해야한다면 UserCustom 을 먼저 수정한다.
        UserCustom userCustom = new UserCustom(memberDTO.getUsername()
                , memberDTO.getPassword()
                , enabled, accountNonExpired, credentialsNonExpired, accountNonLocked
                , authorities(memberDTO)
                , memberDTO.getUser_email()
                , memberDTO.getUser_name() // 이름
        );

        return userCustom;
		}

    // DB에 등록된 권한에 따라 유저권한 부여 user_role
    private static Collection authorities(MemberDTO memberDTO){
        Collection authorities = new ArrayList<>();
        // DB에 저장한 USER_ROLE 이 1이면 ADMIN 권한, 아니면 ROLE_USER 로 준다.
        if(memberDTO.getUser_role().equals("1")){
            authorities.add(new SimpleGrantedAuthority("ADMIN"));
        }else{
            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        }
        return authorities;
    }
}


데이터가 제대로 들어가는지 확인해보겠습니다.


@RequestMapping("/admin")
public String admin(@AuthenticationPrincipal UserCustom user) {
    System.out.println("================= " + user);
    return "admin";
}

//결과: ================= UserCustom(user_email=test@test.com, user_name=test)



해당 코드는 깃헙에 올려두었습니다.

https://github.com/lemontia/SpringBootBase



반응형

댓글