Web Programming/Java Spring

JPA 를 이용한 Spring Security 로그인 구현(H2 DB)

jinmc 2021. 1. 20. 17:18
반응형

오늘은 드디어 JPA를 사용하여 H2 데이터베이스에 있는 유저 정보를 이용해서 로그인을 구현해 보도록 하겠습니다.

일단 UserRepository를 만듭니다.

 

package com.myBoard.demo.model;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Integer> {
	Optional<User> findByUserName(String userName); 
}

UserRepository는 Interface로써, 실제 함수가 아니라, 함수를 정의해 놓은 것에 불과합니다.

Repository 패턴을 왜 사용하는지, 또 무슨 장점이 있는지는 다음에 알아보도록 하고, 

이 Repository를 어떻게 사용하는지 살펴봅시다.

 

package com.myBoard.demo;

// import 생략

@Service
public class MyUserDetailsService implements UserDetailsService {

	@Autowired
	UserRepository userRepository;
	
	@Override
	public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
		Optional<User> user = userRepository.findByUserName(userName);
		
		user.orElseThrow(() -> new UsernameNotFoundException("Not found: " + userName));
		
		return user.map(MyUserDetails::new).get();
//		return new MyUserDetails(username);
	}

}

그 전 포스트에서 사용했었던 MyUserDetailsService에서 사용합니다.

@Autowired 어노테이션은 userRepository 인터페이스를 implement 하는 class 를 자동으로 만들어서 제공해줍니다.

그럼 그 class는 어디에서 만들어야 할까요? 

만들 필요가 없다! 가 정답입니다. JPA Repository는 자동으로 만들어지고 자동으로 주입된다고 합니다.

 

마지막의 map은, user가 Optional 타입이기 때문에, 

(Optional에 대해서는 www.daleseo.com/java8-optional-before/ 참조)

 

user.map의 의미는, MyUserDetails 클라스의 new function에 user가 있을 경우 대입한 이후, 그 이후 return 되는 Optional을 값을 나타내는 것을 get() function이 하는 것입니다.

 

그럼, MyUserDetails를 한번 볼까요?

 

package com.myBoard.demo.model;

// import 생략

public class MyUserDetails implements UserDetails {
	
	private String userName;
	private String password;
	private boolean active;
	private List<GrantedAuthority> authorities;

	public MyUserDetails(User user) {
		this.userName = user.getUserName();
		this.password = user.getPassword();
		this.active = user.isActive();
		this.authorities = Arrays.stream(user.getRole().split(","))
							.map(SimpleGrantedAuthority::new)
							.collect(Collectors.toList());
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		// TODO Auto-generated method stub
		return authorities;
	}

	@Override
	public String getPassword() {
		// TODO Auto-generated method stub
		return password;
	}

	@Override
	public String getUsername() {
		// TODO Auto-generated method stub
		return userName;
	}

	@Override
	public boolean isAccountNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isEnabled() {
		// TODO Auto-generated method stub
		return active;
	}
	

	
	
}

this.authorities 에 화려한 함수들이 많지만, 결국 이 클라스가 하는 일은, 

constructor에서 User 값을 받아서, 그 parameter들을 채워 넣는 일입니다.

지난번과같이 하드코딩되어있는 값이 아니라, User에서 받은 값들을 채워 넣었기 때문에, 

database의 정보들이 전달됨을 알 수 있습니다.

 

그럼 이제 다 된 걸까요? 

아닙니다! 아직 database 연결이 남았죠!

 

application.properties에 가서, database 연결을 시켜주고, id와 password도 설정해줍니다.

 

spring.datasource.url=jdbc:h2:mem:jinmo
spring.h2.console.enabled=true
spring.datasource.driverClassName=org.h2.Driver
 	
spring.datasource.platform=h2
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

아, 그리고 한 가지 더!

JPA를 사용하기 때문에, data.sql을 사용할 때 이제 sql 문법을 사용해 주어야 합니다.

 

INSERT INTO USER (ID, ACTIVE, PASSWORD, PASSWORD_CONFIRM, ROLE, USER_NAME)
VALUES (1, true, 1234, 1234, 'admin', 'faker');

INSERT INTO USER (ID, ACTIVE, PASSWORD, PASSWORD_CONFIRM, ROLE, USER_NAME)
VALUES (2, true, 1234, 1234, 'admin', 'madlife');

INSERT INTO USER (ID, ACTIVE, PASSWORD, PASSWORD_CONFIRM, ROLE, USER_NAME)
VALUES (3, true, 1234, 1234, 'admin', 'showmaker');

이제 다 됬습니다!

spring boot application을 재시작하고, id/pwd를 넣고 로그인을 하면 

화면이 나옵니다.

반응형