부트 개념과 활용-31.시큐리티 설정 커스터마이징(스프링 시큐리티)
스프링 시큐리티 2부: 시큐리티 설정 커스터마이징
웹 시큐리티 설정
@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(); // http 베이직 사용
}
}
이렇게 구현하면 / 와 /hello 요청은 인증 없이 사용이 가능하다.
실습이니 h2를 활용 간단 테스트
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
@Entity
public class Account {
@Id
@GeneratedValue
private Long id;
private String username;
private String password;
...
public interface AccountRepository extends JpaRepository<Account, Long> {
Optional<Account> findByUsername(String username);
}
임의 유저 생성
@Component
public class AccountRunner implements ApplicationRunner {
@Autowired
AccountService accountService;
@Override
public void run(ApplicationArguments args){
System.out.println("create");
accountService.createAccount("jaeuk", "1234");
}
}
UserDetailsServie 구현
@Service
public class AccountService implements UserDetailsService {
// 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);
}
// 로그인 처리를 할때 해당 메서드 호출. (loadUserByUsername)
@Override
public UserDetails loadUserByUsername(String username) {
Optional<Account> byUsername = accountRepository.findByUsername(username);
// 받을 타입을 미리 정하고 메서드를 생성 (ide 도움 받아서 자동생성), 타이핑도 덜하고 오타 x
Account account = byUsername.orElseThrow(()->new UsernameNotFoundException(username));
// 유저(데이터)가 없으면 익셉션, 있으면 넣어줌.
return new User(account.getUsername(), account.getPassword(), authorities() );
}
private Collection<? extends GrantedAuthority> authorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
}
이 상태로만은 로그인을 못한다.
(아무런 암/복호화가 진행되지 않았기 때문에)
암 복호를 하지 않더라도 noop 으로 아무것도 하지 않겠다고 선언해줘야 한다.
PasswordEncoder 설정 및 사용
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#core-services-password-encoding
암/복호도 하지 않는 경우 (noop)
시큐리티 설정에서
@Bean
public PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
PasswordEncoder 빈으로 선언해주면 되고,
암/복호 사용하는 경우
@Bean
public PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
이렇게 하면 저장할때도 인코딩 해서 저장해야 한다.(서비스)
@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}$2a$10$VQlC.oupBp3P8rnEHXQWyegdtdV.LGc06S90EPGUCKVLQDDRktb16
이런 식으로 인코딩 되서 저장되는 걸 볼 수 있다.