Web Programming/Java Spring

Spring Security 를 이용해서 UserDetailService 사용하기

jinmc 2021. 1. 14. 21:54
반응형

이 포스팅은 지난 포스팅에서 이어서 나온 내용입니다.

지난 포스팅에서는 WebSecurityConfig를 만들어서 커스텀 로그인을 만들었습니다.

home과 / 는 로그인을 하지 않아도 접속하게 만드는 것이 저번 포스팅까지 하였습니다.

 

package com.myBoard.demo;

// import 생략...

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	
	
	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/css/**", "/vendor/**", "/js/**", "/images/**", "/h2-console/**");
	}
	
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		
		http
				.authorizeRequests()
				.antMatchers("/home", "/").permitAll()
				.anyRequest().authenticated()
				.and()
				.formLogin()
				.loginPage("/login")
				.permitAll();
	}
    
}    

과연 이 다음은 어떻게 될까요?

이 이후엔 Spring Security에서 주어지는 UserDetailService를 이용해서 로그인을 구현합니다.

그걸 위해서는 WebSecurityConfig에 다음을 추가합니다.

 

package com.myBoard.demo;

// import 생략..

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
	UserDetailsService userDetailsService;
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService);
	}
    
	@Bean
	public PasswordEncoder getPasswordEncoder() {
		return NoOpPasswordEncoder.getInstance();
	}		

}

@Autowired 어노테이션은 UserDetailService 인터페이스를 implement하는 클래스를 찾아서 주입해 주겠다는 어노테이션 입니다.

자바에서는 하나의 인터페이스 당 하나의 클래스만 implement 할 수 있기 때문에, 어디에 만들든 찾을 수 있습니다. 그럼 userDetailService를 한번 찾아봅시다. 굳이 userDetailService의 이름일 필요는 없습니다. UserDetailService를 implement 하기만 하면 됩니다. 서비스에 대해서는 굉장히 좋은 포스트가 있어서 보면 이해가 훨씬 좋을 것입니다.

onlyformylittlefox.tistory.com/13   ㅁㄴㅇㄹ

package com.myBoard.demo;

// import 생략

import com.myBoard.demo.model.MyUserDetails;

@Service
public class MyUserDetailsService implements UserDetailsService {

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {	
		return new MyUserDetails(username);
	}

}

UserDetailService는 의외로 하는일이 별로 없습니다. username이라는 string을 받고, MyUserDetails를 return 하는 것입니다. 

그리고 MyUserDetail은 Spring Securtiy에서 나온 interface입니다.

package com.myBoard.demo.model;

// import 생략..

public class MyUserDetails implements UserDetails {
	
	private String userName;

	public MyUserDetails(String userName) {
		this.userName = userName;
	}
	
	public MyUserDetails() {
		
	}
	
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
	}

	@Override
	public String getPassword() {
		return "pass";
	}

	@Override
	public String getUsername() {
		return userName;
	}

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}

	
	
}

 

여기서 잘 보면, getPassword 함수에 하드코딩으로 "pass"를 넣었음을 알 수 있습니다.

결국 우리가 하는 일은, 로그인 화면에서, 아무 아이디를 넣었을 때, 그 myUserDetail이 생성되고 그 암호는  "pass"가 되고 있습니다.

이로, 로그인 화면에서 아무 아이디나 쳐 넣고, 암호에 "pass"라고 넣으면 로그인이 되는 희한한 현상이 보임을 알 수 있습니다.

 

여기서 두 가지 주의할 점이 있는데, MyUserDetailService 위에 @Service 어노테이션이고, (이거 없으면 안됩니다)

그리고 WebSecurityConfig에서 PassWordEncoder를 오버라이드 해서

return NoOpPasswordEncoder.getInstance(); 를 해야지 됩니다.

 

 

반응형