[Spring JPA ] - 시큐리티 회원가입 -8

JEONG SUJIN·2022년 11월 20일
0

스프링부트 JPA

목록 보기
9/24

시큐리티로 회원가입 후 로그인은
form태그안에 버튼을 넣었기 때문에 클릭시 submit이 됨,
버튼에 타입을 지정해주지 않으면 자동 타입은 submit

login.jsp

form action="/auth/loginProc"에 주소추가

<form action="/auth/loginProc" method="post">
		<div class="form-group">
			<label for="username">username:</label> <input type="text" 
				class="form-control" placeholder="Enter username" name="username" id="username">
		</div>
		
		
		<div class="form-group">
			<label for="password">password</label> <input type="password"
				class="form-control" placeholder="Enter password" name="password" id="password">
		</div>
		
		<div class="form-group form-check">
			<label class="form-check-label"> <input name="remember"
				class="form-check-input" type="checkbox"> Remember me
			</label>
		</div>
		
		<button id="btn-login" class="btn btn-primary">로그인 </button>
		
	</form>

SecurityConfig.java

apiController로 회원가입은로직은 했지만,로그인 시큐리티가 확인하기 위해서 아래에
loginProcessingUrl("/auth/loginProc") 추가

 @Bean	
	 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
          
	        http
	        .csrf().disable()//csrf 토큰 비활성화 (테스트시걸어두는게 좋음)
	        .authorizeRequests()
	        .antMatchers("/","/auth/**","/js/**","/css/**", "/images/**").permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .formLogin()
            .loginPage("/auth/loginForm")
            .loginProcessingUrl("/auth/loginProc");//스프링 시큐리티가 로그인을 가로채서 대신 로그인을 해준다.
            .defaultSuccessUrl("/"); //정상적으로 요청이 완료
	        
	             
	        return http.build();
	    }
     	 

User오브젝트 타입이 안맞아서 클래스를 하나 생성해야한다.

User오브젝트에 UserDetails 오브젝트를 생성해야한다.

로그인을 요쳥하고 세션에 등록해야하는데, 타입이 안맞아서 타입을 맞춰줘야한다.

PrincipalDetail.java

config안에 패키지마 "auth"만들고 auth안에 PrincipalDetail 클래스 생성


/*
 * 
 * UserDetails 추상메서드를 들고있는데 이걸 오버라이딩 해야한다. 
 * 
 * 
 *스프링시큐리티가 로그인 요청을 가로채서 로그인을 진행하고 완료가 되면 
 *UserDetail타입의 오브젝트를스프링시큐리티의 고유한세션저장소에 저장을 해준다. 
 * */
public class PrincipalDetail implements UserDetails {

	// 오브젝트
	private User user; // 객체를 품고있는거, 콤포지션

    //생성자
    public PrincipalDetail(User user) {
    	this.user = user;    	
    }
    
    
	@Override
	public String getPassword() {

		return user.getPassword();
	}

	@Override
	public String getUsername() {
		return user.getUsername();
	}

	// 계정이 만료되지않았는지 리턴 (true:만료안됨)
	@Override
	public boolean isAccountNonExpired() {

		return true;
	}

	// 계정이 잠겨있는지, 안잠겨있는지 리턴 (true:잠기지않음)
	@Override
	public boolean isAccountNonLocked() {

		return true;
	}

	// 비밀번호가 만료되지 않았는지 리턴한다.(true:만료안됨)
	@Override
	public boolean isCredentialsNonExpired() {

		return true;
	}

	// 계정활성화여부 (true:활성화)
	@Override
	public boolean isEnabled() {

		return true;
	}

	// 계정이 갖고있는 권한 목록을 리턴한다.(권한이 여러개 있을 수 있어서 for문을 돌려야 하는데 현재는 한개만 )
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		
		Collection<GrantedAuthority> collectors = new ArrayList<>();
//		collectors.add(new GrantedAuthority() {
//			@Override
//			public String getAuthority() {
//				//ROLE_이건 규칙
//				return "ROLE_" + user.getRole(); //ROLE_USER , ROLE_ADMIN
//			}
//		});
		
		//람다식으로 
		collectors.add(()->{return "ROLE_" + user.getRole();});
		return collectors;
	}
}

시큐리티가 대신 로그인해주는데 password를 가로채기할때 해당 password가 뭘로 해쉬가 되어
회원가입이 되었는지 알아야, 로그인할 때 같은해쉬로 암호화해서 db에있는 해쉬랑 비교할 수있음

SecurityConfig.java


//추가해준다.

protected void configure(AuthenticationManagerBuilder auth) throws Exception{
		auth.userDetailsService(null).passwordEncoder(encodePWD());
	}

현재 userDetailsService(null) 부분에 들어가야되는파일은 아직 만들지 않았음. 그래서 auth패키지에서 PrincipalDetailService.java 파일을 생성

UserRepository.java

findByUsername 찾는 쿼리문추가

public interface UserRepository extends JpaRepository<User, Integer>{
	//네이밍쿼리
    //select* from user where username = 1?
	Optional<User> findByUsername(String username);

}

PrincipalDetailService.java

시큐리티를 사용할 때

✅ findByUsername 로직을 반드시 만들어줘야,
우리가 원하는 유저타입을 넣을 수 있다.

@Service
public class PrincipalDetailService implements UserDetailsService {
    
	@Autowired
	private UserRepository userRepository;
	
	
	//스프링이 로그인요청을 가로챌때, usernname,password변수 2개를 가로채는데
	//password 부분처리는 알아서함.
	//username이 db에 있는지만 확인하면 됨
	
	@Override
	public UserDetails loadUserByUsername(String username) throws          UsernameNotFoundException {
		User principal= userRepository.findByUsername(username)
				.orElseThrow(()->{
			return new UsernameNotFoundException("해당사용자를 찾을 수 없습니다. " + username);
		});
		return new PrincipalDetail(principal); //시큐리티세션에 유저정보가 저장이 됨
	}
}

User principal를 PrincipalDetail에 담아주고
PrincipalDetail을 리턴해준다.

그럼타입이 UserDetails 타입이니까..!
우리가 만든 유저오브젝트를 시큐리티에 넣어서 담아줄 수 있는 것.

PrincipalDetail.java

public class PrincipalDetail implements UserDetails {
// 오브젝트
    private User user; // 객체를 품고있는거, 콤포지션	
//생성자
    public PrincipalDetail(User user) {
    	this.user = user;    	
    }
}

그리고 이제 다시 로그인을 실행

userDetailsService(null) 부분에 들어갈 로직을 만들었기 때문에 로직을 넣어주기 위해 다시
SecurityConfig.java로 가서 수정.

SecurityConfig.java


@RequiredArgsConstructor
public class SecurityConfig{
    
    //생성자 주입 
	private PrincipalDetailService principalDetailService;
    
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
		auth.userDetailsService(principalDetailService).passwordEncoder(encodePWD());
	}
    

내가 회원가입할때 입력했던 비밀번호를 입력하면

로그인이 정상적으로 완료 !

데이터베이스에는 해쉬화되어있는거 완료♥️

profile
기록하기

0개의 댓글