3 로그인
로그인 서비스
import com.post_show_blues.vine.domain.member.Member;
import com.post_show_blues.vine.domain.member.MemberRepository;
import lombok.RequiredArgsConstructor;
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;
@RequiredArgsConstructor
@Service //IoC //로그인 요청하면 실행
public class PrincipalDetailsService implements UserDetailsService {
private final MemberRepository memberRepository;
//1. 패스워드는 알아서 체킹하니까 신경 x
//2. 리턴이 잘 되면 자동으로 UserDetails타입 세션 만듦
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Member memberEntity = memberRepository.findByEmail(username);
System.out.println("memberEntity = " + memberEntity);
if(memberEntity == null){
return null;
}else{
return new PrincipalDetails(memberEntity);
}
}
}
로그인 요청 시 실행되는 서비스로 해당 아이디+패스워드가 유효한지 체킹한다
우리 서비스에서는 email로 로그인 해 findByEmail을 사용했다.
UserDetails
package com.post_show_blues.vine.config.auth;
import com.post_show_blues.vine.domain.member.Member;
import lombok.Getter;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
@Getter
@Setter
public class PrincipalDetails implements UserDetails {
private Member member;
public PrincipalDetails(Member member) {
this.member = member;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return member.getPassword();
}
@Override
public String getUsername() {
return member.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
loadUserByUsername이 UserDetails 타입을 리턴하는데 해당 타입은 커스텀이 필요하다
isAccountNonExpired(), isAccountNonLocked(), isCredentialsNonExpired(), isEnabled() 는 false로 돼있으면 로그인을 할 수 없다고 한다.
1 유저가 로그인을 시도 (http request)
2. AuthenticationFilter 에서부터 user DB까지 타고 들어감
3. DB에 있는 유저라면 UserDetails 로 꺼내서 유저의 session 생성
4. spring security의 인메모리 세션저장소인 SecurityContextHolder 에 저장
5. 유저에게 session ID와 함께 응답을 내려줌
6 이후 요청에서는 요청쿠키에서 JSESSIONID를 까봐서 검증 후 유효하면 Authentication를 쥐어준다
출처 https://growing-up-constantly.tistory.com/41
쨌든 UserDetailsService가 user 로그인과 인증된 user의 세션 형성에 기여한다고 생각하면 될 듯 하다
어려운 보안의 세계,,,
아직 UI 작업이 안 들어가서 테스트를 어떻게 할 까 고민했는데 Application 클래스에서 실행 가능한 방법이 있었다
DB에 데이터 삽입
import com.post_show_blues.vine.domain.member.MemberRepository;
import com.post_show_blues.vine.dto.Auth.SignupDto;
import com.post_show_blues.vine.service.AuthService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@SpringBootApplication
@EnableJpaAuditing
@RequiredArgsConstructor
public class VineApplication implements CommandLineRunner {
private final AuthService authService;
public static void main(String[] args) {
SpringApplication.run(VineApplication.class, args);
}
@Override
public void run(String... args) throws Exception{
SignupDto memberEntityA = SignupDto.builder()
.name("memberA")
.email("a")
.nickname("aaaa")
.password("a")
.phone("010-0000-0000")
.university("덕성대학교")
.build();
authService.join(memberEntityA.toEntity());
}
}
Application 클래스는 항상 Run 하면 가장 먼저 실행되는 클래스이다.
여기서 CommandLineRunner 클래스를 구현해 run 메소드를 오버라이드하면
프로젝트 Run과 동시에 원하는 코드를 실행할 수 있다.
예쁘게 들어감 ㅎㅎ
비밀번호는 BCryptPasswordEncoder를 이용해 암호화 후 저장됐다
controller에서 /login url을 연결 안 했어도 spring security에서 알아서 로그인 창을 만들어주니 그냥 쓰면 된다
아이디 a, 비번 a로 로그인 하면 404가 뜬다 해당 페이지가 없다는 거 ㅎㅎㅎ
난 의심 많은 사람이라 비번 다른 걸로도 해봤다
아이디 a, 비번 b로 하면 자격 증명에 실패했다고 뜬다. 비밀번호 오류랑 같은 의미인듯
아이디 b, 비번 b로 하면 return null이라고 뜬다. 해당 회원이 없다는 뜻인듯
스프링 시큐리티가 꽤 어렵,,, 사실 여기서 핸들러도 해야되는데 어려워 보여서 재꼈다 ㅎ
전체적으로 다 만든 다음에 다시 핸들러로 넘어와야겠다
코드 깃헙 주소 https://github.com/JMine97/vine