부트 개념과 활용-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 구현

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

@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
이런 식으로 인코딩 되서 저장되는 걸 볼 수 있다.




© 2019. by jaeuk