시큐러티 들어가기 전에, 컨트롤러 만들기.
@Controller
public class HomeController {
@GetMapping(/"Hello")
public String hello() {
return "Hello";
}
}
@RunWith(SpringRunner.class)
@WebMvcTest(HomeController.class)
public class HomeControllerTest {
@autowired
MockMvc mockMvc;
@Test
public void hello() throws Exception {
mockMvc.perform(get("/hello"))
.andDo(print())
.andExpect(status().isOK())
.andExpect(view().name("Hello"));
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
모든 요청이 스프링시큐러티로 인해 인증이 필요하게 됨.
베이직어센티케이션이(컨텐츠 타입이 아니라, 어셉트 헤더에 따라 달라짐- 이 응답을 브라우저 받으면 브라우저는 브라우저가 내장하고 있는 안 이쁜 베이직어센티케이션폼을 띄우게 되어 있음.)
@Configuration
@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)
@EnableConfigurationProperties(SecurityProperties.class)
@Import({SpringBootWebSecurityConfiguration.class, Web~})
puvlic class SecurityAutoConfiguration {
@Bean
@Conditional IOnMissingBean(uthenticationEventPublisher.class)
public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
retuern new DefaultAuthenticationEventPublisher(publisher);
}
}
이벤트에 핸들러 등록해서 유저의 상태를 변경하는 등 여러가지를 할 수 있음.
스프링부트가 해주는 것: 유저디테일 서비스가 없을 때, 어센티케이션 프로바이더가 없는 경우에만 인메모리로 유저디테일즈매니저를 만들어서 랜덤하게 유저를 생성해줌.
대게는 유저디테일 서비스를 등록해주기 때문에, 스프링부트가 지원하는 시큐리티 관련 기능은 쓸 일이 별로 없음.
테스트 할 때는
@WithMockUser
어노테이션 붙여주면 가짜유저 등록해서 테스트 해줌.
-> 이 클래스 안에 들어있는 모든 메소드 테스트 가능.
@Configuration
public class WebSecurityConfig extents WebSecurityConfigurerAdapter {
@Override
protected void configure(HJttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/hello").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
}
보통 서비스계층에 인터페이스 구현
@Service
public class AccountService implements UserDetailsService {
@Autowired
private AccountRepository accountRepository
...
}
implements UserDetailsService
있어야만 스프링부트가 맘대로 유저 생성 안 함. UserDetailsService를 이용해서 로그인 처리가 되는 것.
로그인 처리를 할 때 loadUserByUsername
이 호출이 됨.
로그인할 때 아이디, 패스워드 등록하면 그 정보가 여기로 옴. username에 해당하는 실제 user정보(안에 password가 들어있음, 같으면 로그인, 다르면 예외 던짐.)를 확인함.
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundE {
Optional<Account> nyusername = accountRepository.findByUsername(username);
//유저를 가져옴.
byUsername.orElseThrow(() -> new UsernamedNotFoundException(username));
//데이터가 없으면
//UserDetails는 핵심적 유저의 중요정보 담은 인터페이스
//이 인터페이스의 기본 구현체를 스프링시큐리티가 유저라는 이름으로 제공을 함. 어카운트 정보(계정 정보)를 유저디테일즈로 변환해서 리턴!
return new User(account.getUsername(), account.getPassword(), authorities());
//이렇게 하면 어쏘리티스 메소드를 밑에 만들어 줘야함.
}
private Collection<? extends GrantedAuthority> authorities() {
return Arrays.asList(new SimpleCrantedAuthority("ROLE_USER"));
}