728x90
1. 기본인증
-> 처음 애플리케이션 시작하면 콘솔에 있는 랜덤 비밀번호 사용
Id : user (고정)
password : 콘솔창 확인
2. yml에 사용자 추가하기
application.yml 에 사용자 추가하기
spring:
security:
user:
name: user1
password: 1234
roles: USER
3. UserDetailsService 서비스 빈을 추가하기
USER , ADMIN 으로 테스트하기 위해서는 yml 에 추가하는 것으로는 불가능
서비스빈을 사용해 여러명을 등록
설정추가 ( @Configuration , @Bean 사용 )
@Configuration //설정 정보를 추가해준다
public class SecurityRoleTest {
@Bean // 스프링 컨테이너에 빈으로 등록
UserDetailsService users () {
UserDetails user1 = User.builder()
.username("user1")
.password(passwordEncoder().encode("1234"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("1234"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user1, admin); // 인메모리에 저장
}
@Bean
PasswordEncoder passwordEncoder() { // 비밀번호 암호화
return new BCryptPasswordEncoder();
}
}
TestController 추가
@RestController
public class TestController {
@Secured({"ROLE_USER", "ROLE_ADMIN"}) //해당 url 접근은 user 와 admin 가능
@GetMapping("/user")
public SecurityMessage user() {
return SecurityMessage.builder()
.message("user page")
.auth(SecurityContextHolder.getContext().getAuthentication())
.build();
}
@Secured({"ROLE_ADMIN"}) // 해당 url 접근은 admin만 가능
@GetMapping("/admin")
public SecurityMessage admin() {
return SecurityMessage.builder()
.message("admin page")
.auth(SecurityContextHolder.getContext().getAuthentication())
.build();
}
}
SecurityMessage 클래스 생성
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SecurityMessage {
private String message;
private Authentication auth;
}
4. WebSecurityConfigurerAdapter 를 사용하기
@EnableWebSecurity // SpringSecurityFilterChain 에 자동으로 포함
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable() // csrf 무시
.formLogin() // 폼로그인 설정
.loginPage("/login") // 로그인페이지는 "/login"
.successForwardUrl("/") // 성공하면 / url 로 이동
.failureUrl("/login?error=true"); // 실패하면 해당 url 로 이동
}
// 테스트 유저 만들기
@Bean
UserDetailsService users () {
UserDetails user1 = User.builder()
.username("user1")
.password(passwordEncoder().encode("1234"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("1234"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user1, admin);
}
// 비밀번호 암호화
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
5. 로그인 화면 커스터마이징 하기
타임리프를 이용해서 만들기
6. Junit으로 테스트하기
@WebMvcTest
public class UserAccessTest {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@Autowired
PasswordEncoder passwordEncoder;
@Test
@DisplayName("2. user 로 user 페이지에 접근할 수 있다.")
@WithMockUser(username = "user1", roles = "USER")
void test_user_access_userPage() throws Exception {
String resp = mockMvc.perform(get("/user"))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
System.out.println("resp = " + resp); // resp = {"message":"user page"}
SecurityMessage message = objectMapper.readValue(resp, SecurityMessage.class);
System.out.println("message = " + message);
assertEquals("user page", message.getMessage());
}
@Test
@DisplayName("1. user 로 admin 페이지에 접근할 수 없다.")
@WithMockUser(username = "user1" , roles = "USER")
void test_user_access_adminPage() throws Exception {
mockMvc.perform(get("/admin"))
.andExpect(status().isForbidden());
}
@Test
@DisplayName("3. admin 으로 user 페이지와 admin 페이지에 접근할 수 있다.")
@WithMockUser(username = "admin" , roles = "ADMIN")
void test_admin_access_userPage_adminPage() throws Exception {
String resp = mockMvc.perform(get("/admin"))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
SecurityMessage message = objectMapper.readValue(resp, SecurityMessage.class);
assertEquals("admin page", message.getMessage());
String resp1 = mockMvc.perform(get("/user"))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
SecurityMessage message1 = objectMapper.readValue(resp1, SecurityMessage.class);
assertEquals("user page", message1.getMessage());
}
@Test
@DisplayName("4. 로그인 페이지는 아무나 접근 가능해야 한다.")
void test_all_access_loginPage() throws Exception {
mockMvc.perform(get("/login"))
.andExpect(status().isOk());
}
@Test
@DisplayName("5. 홈페이지는 로그인 하지 않은 계정은 들어올 수 없다.")
void test_notLogin_notAccess_homePage() throws Exception {
mockMvc.perform(get("/")).andExpect(status().is3xxRedirection());
mockMvc.perform(get("/user")).andExpect(status().is3xxRedirection());
mockMvc.perform(get("/admin")).andExpect(status().is3xxRedirection());
}
}
참고
https://www.youtube.com/watch?v=MNEgiFeUy_U&list=PLcaKom3xthg63Qq5qCG7EG7XY3nN05ypd&index=1
728x90
'Spring > Spring-Security' 카테고리의 다른 글
Spring Security + JWT 로그인 구현하기 (Access Token) (0) | 2023.01.23 |
---|---|
SpringSecurity 와 JWT 의 구조, 동작 과정 (0) | 2022.10.23 |
JWT (Json Web Token) 의 개념 (0) | 2022.10.19 |
세션(서버) 기반 VS 토큰 기반 차이 (0) | 2022.10.19 |
스프링 시큐리티 설정 추가 (0) | 2022.09.14 |
댓글