인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

권영언님의 프로필 이미지
권영언

작성한 질문수

스프링과 JPA 기반 웹 애플리케이션 개발

로그인과 로그인 유지에서

해결된 질문

작성

·

266

0

안녕하세요! 로그인과 로그인 유지에 대해 질문이 있습니다!!

강의에서는 이메일과 닉네임으로 모두 로그인이 가능하게 되어있는데

로그인을 할 때 이메일로만 로그인이 가능하도록 하면서 로그인을 했을 때 타임리프에서 #authentication.name으로 닉네임을 가져올 수 있는 방법이 있을까요??

아래와 같이 UserAccount에서 username 자리에 account.getNickname()를 넣어주어야  #authentication.name 에 닉네임이 들어갈텐데..

@Getter
public class UserAccount extends User { 

    private Account account;
    public UserAccount(Account account) {
        super(account.getNickname(), account.getPassword(), List.of(new SimpleGrantedAuthority("ROLE_USER")));
        this.account = account;
    }
}

 이메일로만 로그인이 가능하도록 하려면 loadUserByUsername 메서드에서 이메일로 찾지 못한 경우 닉네임으로 유저를 찾도록 하는 코드를 지워야 하고, 그렇게 되면 RememberMe 를 통한 로그인 유지에서 jsessionid를 지운 경우 Remember-me 쿠키에 담긴 username이 닉네임이므로 loadUserByUsername 메서드에서 account를 찾을 수 없게 됩니다.

    @Transactional(readOnly = true)
    @Override
    public UserDetails loadUserByUsername(String emailOrNickname) throws UsernameNotFoundException {
        Account account = accountRepository.findByEmail(emailOrNickname);
        if(account == null){ 
            account = accountRepository.findByNickname(emailOrNickname);
        }
        if(account == null){ 
            throw new UsernameNotFoundException(emailOrNickname);
        }
        return new UserAccount(account);
    }

이러한 경우 어떻게 해야  User클래스의 username에 닉네임을 넣었을 때, 이메일로만 로그인이 가능하도록 하면서 로그인 유지 기능을 정상적으로 동작시킬 수 있을지 궁금합니다..!!

답변 4

1

백기선님의 프로필 이미지
백기선
지식공유자

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService); // 이메일로 로그인하는 UserDetails 구현체
}

SecurityConfig에 이 설정을 추가해 보시겠어요? 스프링 시큐리티가 사용할 기본 AuthManager에 이메일로만 로그인하는 UserDetailsService를 설정하는 코드입니다.

1

백기선님의 프로필 이미지
백기선
지식공유자

로그인을 할 때 이메일로만 로그인이 가능하도록 하면서 로그인을 했을 때 타임리프에서 #authentication.name으로 닉네임을 가져올 수 있는 방법이 있을까요??

> 네 그건 말씀하신대로 이메일로 Account 조회해서 User의 username에 Account의 닉네임을 넣어주면 됩니다.

두번째 질문에 대한건, 그럼 RememberMe 필터가 사용할 UserDetailsService를 새로 하나 더 만들어서 필터에 설정해줘야겠네요. 그 UserDetailsService는 닉네임으로 유저를 조회하는 코드가 될겠네요.

http.rememberMe()
.userDetailsService(userDetailsService)
.tokenRepository(tokenRepository());

즉 여기서 참조할 userDetailsSerivce를 다른걸로 바꿔야죠. RememberMeUserDetailsService같은걸 만들어서요.

0

권영언님의 프로필 이미지
권영언
질문자

감사합니다!! 설정해주니까 해결됐습니다..!!

저렇게 기본 UserDetailsService를 설정할 수 있군요!

0

권영언님의 프로필 이미지
권영언
질문자

답변 감사합니다!!

말씀하신대로 구현을 해보니, 아이디와 이메일 모두 로그인이 안되는 현상이 발생했습니다.

사용자 정보를 찾아오지 못하는 것 같은데

UserDetailsService가 2개이기 때문에 다른 처리를 해줘야 하는건지 궁금합니다..!

- RememberMeUserDetailsService

@Service
@RequiredArgsConstructor
public class RememberMeUserDetailsService implements UserDetailsService {

private final AccountRepository accountRepository;

@Transactional(readOnly = true)
@Override
public UserDetails loadUserByUsername(String nickname) throws UsernameNotFoundException {

Account byNickname = accountRepository.findByNickname(nickname);

if (byNickname == null) {
throw new UsernameNotFoundException(nickname);
}
return new UserAccount(byNickname);

}
}

http.rememberMe()
.userDetailsService(rememberMeUserDetailsService)
.tokenRepository(tokenRepository());

- AccountService

@Transactional(readOnly = true)
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
Account account = accountRepository.findByEmail(email);

if(account == null){
throw new UsernameNotFoundException(email);
}
return new UserAccount(account); // User 를 확장한 UserAccount 클래스에 유저 정보와 권한을 삽입하여 반환
}
권영언님의 프로필 이미지
권영언

작성한 질문수

질문하기