Java/Spring Boot

[Spring Boot] Spring Security 설정 커스터마이징

hh_lin 2022. 5. 1. 23:20

1. 웹 시큐리티 설정

  • 아래와 같은 화면에서 My에만 인증이 필요하게 변경하고 싶은 경우
  • WebSecurityConfigurerAdapter를 상속받는 Config 파일 생성
    -> 이렇게 되면 Spring Boot가 제공하는 Security 자동설정은 적용되지 않음

 

 

 

 

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
            .antMatchers("/", "/hello").permitAll()
            .anyRequest().authenticated()
            .and()
         .formLogin()
            .and()
         .httpBasic();
   }
}

-> 루트와 /hello에 대해서만 전부 허용하고 나머지 모든 요청은 인증 필요

-> form 인증과 basic 인증 사용

 

 

 

 

 

 

 

 

 

 

2. UserDetailsService 구현

  • 보통 유저 정보를 관리하는 서비스 계층에다 UserDetailsService 인터페이스를 구현
  • 이 타입의 빈이 등록되어 있으면 Spring Boot가 만들어주는 기본 사용자가 생성되지 않음
  • 로그인 시 UserDetailsService가 가지고 있는 loadUserByUsername() 메소드 호출됨

@Service
public class AccountService implements UserDetailsService {

	@Autowired
	private AccountRepository accountRepository;

	public Account createAccount(String username, String password) {
		Account account = new Account();
		account.setUsername(username);
		account.setPassword(password);

		return accountRepository.save(account);
	}

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		Optional<Account> byUsername = accountRepository.findByUsername(username);

		// byUsername에 데이터가 없으면 exception, 있으면 account에 저장
		Account account = byUsername.orElseThrow(() -> new UsernameNotFoundException(username));

		// UserDetails는 서비스에 구현되어있는 유저 정보들의 인터페이스
		// 인터페이스의 기본 구현체를 spring security가 User라는 이름으로 제공
		// ROLE_USER라는 권한을 가진 account 정보를 UserDetails로 변환
		return new User(account.getUsername(), account.getPassword(), authorities());
	}

	private Collection<? extends GrantedAuthority> authorities() {
		return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

3. PasswordEncoder 설정 및 사용

@Component
public class AccountRunner implements ApplicationRunner {

   @Autowired
   AccountService accountService;

   @Override
   public void run(ApplicationArguments args) throws Exception {
      Account hhlin = accountService.createAccount("hhlin", "1234");
      System.out.println(hhlin.getUsername() + " password: " + hhlin.getPassword());
   }
}

 

 

유저 정보 생성 후 실행해도 My 접근 시 오류 발생

-> java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"

 

 

NoOpPasswordEncoder를 사용해서 PasswordEncoder를 빈으로 등록하면

My에 접근은 가능하지만 인코딩을 사용하지 않는 가장 안좋은 방법 (절대 사용하지 말 것)

-> PasswordEncoderFactories.createDelegatingPasswordEncoder() 사용할 것

@Bean
public PasswordEncoder passwordEncoder() {
   // return NoOpPasswordEncoder.getInstance();
   return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

 

 

Service에서 PasswordEncoder를 주입받고, password를 인코딩해서 저장

@Service
public class AccountService implements UserDetailsService {

   @Autowired
   private AccountRepository accountRepository;

   @Autowired
   private PasswordEncoder passwordEncoder;

   public Account createAccount(String username, String password) {
      Account account = new Account();
      account.setUsername(username);
      account.setPassword(passwordEncoder.encode(password));

      return accountRepository.save(account);
   }
}

 

 

어플리케이션 실행 시 bcrypt로 인코딩된 것 확인 가능

 

 

 

 

 

 

 

 

 

 

 

 

 

 

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard

 

스프링 부트 개념과 활용 - 인프런 | 강의

스프링 부트의 원리 및 여러 기능을 코딩을 통해 쉽게 이해하고 보다 적극적으로 사용할 수 있는 방법을 학습합니다., - 강의 소개 | 인프런...

www.inflearn.com

https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#jc-authentication-userdetailsservice

https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#core-services-password-encoding