솔적솔적

Spring Boot Security - 시큐리티 회원가입, 로그인 본문

Back-end/Spring Boot Security

Spring Boot Security - 시큐리티 회원가입, 로그인

솔솔봄향기 2022. 2. 7. 17:32

| 시큐리티 회원가입

 

templates안에 loginForm.html 생성

나머지는 모두 권한이 허용되어있기 때문에 /login 입력 시 작성한 loginForm.html가 보인

 

이제회원가입을 하기 위해 객체를 만들어보자

 

model 패키지 생성 후 User 클래스 생성하여 객체 정의한다.

@Entity
@Data
public class User {
	@Id//primary key
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	
	private int id;
	private String username;
	private String password;
	private String email;
	private String role; //ROLE_USER, ROLE_ADMIN
	
	private String provider;
	private String providerId;
	//private Timestamp loginDate;
	@CreationTimestamp
	private Timestamp createDate;
}

 

DB에 User라는 테이블이 만들어졌는지 확인

 

joinForm.html 회원가입 만들기

@ResponseBody을 써두었기 때문에 회원가입 시 화면에는 join이 나와야 정상작동, 

 

Repository 패키지 생성 안에 UserRepository 인터페이스를 만들자

 

public interface UserRepository extends JpaRepository<User, Integer>{

}

JpaRepository가 CRUD함수를 들고 있다

@Repository라는 어노테이션이 없어도 IoC가 되는데, 그 이유는 위의JpaRepository를 상속했기 때문이다.

 

controller단의 join에 이렇게 셋팅을 하면 회원가입은 잘 되어지지만, 패스워드가 암호화가 되어야한다.

user.setRole("ROLE_USER");
userRepository.save(user);

SecurityConfig.java안에 

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Bean
	public BCryptPasswordEncoder encodePwd() {
		return new BCryptPasswordEncoder();
	}

@Bean 어노테이션을 적어서 해당 메서드의 리턴되는 오브젝트를 IoC로 등록시켜준다.

 

IndexController안에는 Autowired와 함께 join부분 추가

@PostMapping("/join")
	public @ResponseBody String join(User user) {
		System.out.println("user"+user);
		user.setRole("ROLE_USER");
		String rawPassword = user.getPassword();
		String endcPassword = bCrpBCryptPasswordEncoder.encode(rawPassword);
		user.setPassword(endcPassword);
		userRepository.save(user); 
		return "redireact:/loginForm";
	}

하고 실행 후 DB를 확인하면

 

| 시큐리티 로그인

추가 코드

.loginProcessingUrl("/login") → /login 주소가 호출이 되면 시큐리티가 낚아채서 대신 로그인을 진행해준다.

로그인 폼에서 form action="/login"로 해주면 시큐리티가 낚아챈다는 것.


.defaultSuccessUrl("/");  로그인이 완료되면 보이는 경로

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable();
		http.authorizeRequests()
		.antMatchers("/user/**").authenticated()
		.antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")//이 권한이 있는 사람만 들어올 수 있게한다.
		.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
		.anyRequest().permitAll()
		.and()
		.formLogin()
		.loginPage("/loginForm")
		.loginProcessingUrl("/login")
		.defaultSuccessUrl("/"); 
	}

 

auth 패키지 생성하고 안에 PrincipaDetails 클래스 생성

 

시큐리티가 /login 주소 요청이 오면 낚아채서 로그인을 진행시킨다.

로그인을 진행이 완려되면 시큐리티session을 만들어준다. 

이 시큐리티가 가지고 있는 session 이있다.

 

시큐리티 자신만의 session공간을 가진다. Security ContextHolder안에 다가 session정보를 저장한다.

 

시큐리티가 가지고있는 세션에 들어갈 수 있는 오브젝트가 정해져있다. 이 객체가 Authentication타입 객체이다.

 

이 Authentication안에는 User정보가 있어야한다.

 

User오브젝트 타입은 UserDetails 타입 객체 

 

시큐리티 세션 영역이있는데 여기에 들어갈 수 있는 객체가 Authentication,

그리고 여기에 user정보를 저장할 때 UserDetails 객체를 꺼내사용하기

 

그러기 위해서 상속 UserDetails  하고 오버라이딩 재정의와 생성자

public class PrincipalDetails implements UserDetails{
	
	private User user;
	
	public PrincipalDetails(User user) {
		this.user=user;
	}

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

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

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

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

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

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

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

}

 

auth패키지안에 PrincipalDetailsSevice 생성 후 

 

//시큐리티 설정에서 loginProcessingUrl("/login"), login 요청이 오면 자동으로 UserDetailsService 타입으로 IoC되어있는 loadUserByUsername함수가 실행
@Service
public class PrincipalDetailsService implements UserDetailsService{
	
	@Autowired
	private UserRepository userRepository;
	
	//시큐리티 session(내부 Authentication(내부 UserDetails) 

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		User userEntity = userRepository.findByUsername(username);
		if(userEntity!=null) {
			return new PrincipalDetails(userEntity);
		}
		return null;
	}

}

[참고] - 인프런 시프링 부트 시큐리티& JWT 강의