RestApi 만들기 - 스프링 시큐리티 적용하기 (12)

반응형
반응형

원래는 스프링 시큐리티에 대해 공부하고 하려다가 
너무 오래 걸릴 것 같아 생략하고 적용하는것부터 진행하려고 한다.
아무튼 스프링 시큐리티를 적용하는 이유는
게시글을 만든 유저만 수정이 가능하게 만들기 위해 적용하는걸로 알고 있다.
아무튼... 적용해보자.

 <dependency>
      <groupId>org.springframework.security.oauth.boot</groupId>
      <artifactId>spring-security-oauth2-autoconfigure</artifactId>
      <version>2.1.10.RELEASE</version>
</dependency>

이것을 추가해줘야 스프링 시큐리티를 사용할 수 있게 된다.
(이글은 백기선님 강의를 보고 작성한 글이기때문에 start.security를 사용하지 되지 않습니다.)
생각해보니 vo를 만들지 않았다.

@Getter @Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Account {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Integer id;
  private String username;
  private String password;
  
  @ElementCollection(fetch = FetchType.EAGER)
  @Enumerated(EnumType.STRING)
  private Set<AccountRole> roles;
}


이제 테스트 코드를 작성해보자.

@SpringBootTest
@Import(RestDocsConfiguration.class)
@ActiveProfiles("test")
class AccountServiceTest {

  @Autowired
  private AccountService accountService;
  @Test
  void loadUser() {
    String username = "klom";
    String password = "1234";
    Account account = Account.builder()
        .username(username)
        .password(password)
        .roles(Set.of(AccountRole.ADMIN, AccountRole.USER))
        .build();
    UserDetails userDetails = accountService.loadUserByUsername(username);
    assertThat(userDetails.getPassword()).isEqualTo(password);
  }
}

간략히 설명하면 account에서 받은 정보랑 accountService에서 구한 패스워드가 일치하는지 확인하는 테스트 코드다.
물론 이것을 실행해봤자 의미가 없다.
1. account는 db에 저장하지 않았다.
2. accountService를 구현하지 않았다.
1번 부터 적용해보자.
적용뒤 실행해보니.

nullPointExeption이 발생했다.
그러면 userService을 수정해주면 된다.

@Service
public class AccountService implements UserDetailsService {

  private final AccountRepository accountRepository;

  public AccountService(
      AccountRepository accountRepository) {
    this.accountRepository = accountRepository;
  }

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    Optional<Account> optAccount = accountRepository.findByUsername(username);
    Account account = optAccount
        .orElseThrow(() -> new UsernameNotFoundException("유저 정보가 존재하지 않습니다."));
    return new User(account.getUsername(), account.getPassword(), authorities(account.getRoles()));
  }

  private Collection<? extends GrantedAuthority> authorities(Set<AccountRole> roles) {
    return roles.stream().map(r -> new SimpleGrantedAuthority("_ROLE"+r.name())).collect(Collectors.toSet());
  }
}

그리고 실행을 해보면...

다행히 성공했다는것을 알 수 있다.
생각해보니 한가지 예외를 빼먹었다.
바로 없는 사용자를 입력했을 경우는 어떻게 처리를 해야할까?

@Test
  void loadEmptyUser() {
    assertThrows(
        UsernameNotFoundException.class,
        () -> {
          String username = "klomlly";
          accountService.loadUserByUsername(username);
        }
    );
  }

이렇게 예외를 처리하면된다.
이 기능은 junit5에 들어온 기능으로 예외 처리를 할때 사용한다고 한다.
이렇게 실행하면 성공한다.
그런데 과연 이 코드가 성공했다고 어떻게 장담할 수 있을까?
그래서 db에 존재하는 유저를 입력했을 경우 어떻게 될까?

@Test
  void loadEmptyUser() {
    String username = "klom";
    String password = "1234";
    Account account = Account.builder()
        .username(username)
        .password(password)
        .roles(Set.of(AccountRole.ADMIN, AccountRole.USER))
        .build();
    accountRepository.save(account);
    assertThrows(
        UsernameNotFoundException.class,
        () -> {
//          String username = "klomlly";
          accountService.loadUserByUsername(username);
        }
    );
  }

대충 코드는 이렇게 수정하였다.
결과는

왜 예외코드가 발생했다고 했는데, 어째서 정상인 코드가 들어왔냐고 말하는 것 같다.

... 

반응형

댓글

Designed by JB FACTORY