- Method Security
- Method Secuity는 애플리케이션의 메소드 레벨에서 보안 규칙을 정의하고 적용할 수 있게 해주는 기능이다.
- SecurityConfig.java
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
return http
.authorizeHttpRequests()
// .requestMatchers(HttpMethod.POST,"/auth/login").permitAll()
// .requestMatchers(HttpMethod.POST,"/auth/signup").permitAll()
//위의 방법을 사용하면 무한 페이지 리다이렉트 될 수 있다...?
// .requestMatchers("/auth/login").permitAll()
// .requestMatchers("/auth/signup").permitAll()
.anyRequest().permitAll()
.and()
.addFilterBefore(emailPasswordAuthFilter(), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(e -> {
e.accessDeniedHandler(new Http403Handler(objectMapper));
e.authenticationEntryPoint(new Http401Handler(objectMapper));
//로그인이 필요한 페이지인데 로그인이 안된 상태에서 접근 했을 때
})
.rememberMe(new Customizer<RememberMeConfigurer<HttpSecurity>>() {
@Override
public void customize(RememberMeConfigurer<HttpSecurity> rm) {
rm.rememberMeParameter("remember")
.alwaysRemember(false)
.tokenValiditySeconds(2592000);
}
}
)
.csrf(AbstractHttpConfigurer::disable)
.build();
}
1. SecurityFilterChain을 보게 되면, 프로젝트가 커지고 컨트롤러가 많아지면 filter의 코드가 길어지면 복잡해질 수 있기 때문에 Controller에 직접 Security를 적용 시킬 수 있다.
@Slf4j
@Configuration
@EnableWebSecurity(debug = true)
@RequiredArgsConstructor
@EnableMethodSecurity
//이것만 달아주면 메서드 시큐리티가 가능하다.
// debug 달면 log가 더 잘뜬다. 운영환경에선 사용하면 안된다.
public class SecurityConfig {
private final ObjectMapper objectMapper;
private final UserRepository userRepository;
2. 클래스 상단에 @EnableMethodSecurity를 달아주게 되면, Controller에서 Spring EL을 통해 해당 경로에 대한 인증을 수행할 수 있다.
- PostController.java
@Slf4j
@RestController
@RequiredArgsConstructor
public class PostController {
private final PostService postService;
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/posts")
public void post(@RequestBody @Valid PostCreate request) {
request.validate();
postService.write(request);
}
@GetMapping("/posts/{postId}")
public PostResponse get(@PathVariable Long postId) {
return postService.get(postId);
}
@GetMapping("/posts")
public List<PostResponse> getList(@ModelAttribute PostSearch postSearch) {
return postService.getList(postSearch);
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PatchMapping("/posts/{postId}")
public void edit(@PathVariable Long postId, @RequestBody @Valid PostEdit request) {
postService.edit(postId, request);
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/posts/{postId}")
public void delete(@PathVariable Long postId) {
postService.delete(postId);
}
}
3. PreAuthorize, PostAuthorize를 통해 메소드 호출 전 후에 사용자에 대한 권한을 검사할 수 있다.
@PreAuthorize("hasRole('ROLE_ADMIN')")
4. 현재 위 Controller에서는 PreAuthorize를 사용하였고, 해당 경로에 접근하기 이전에 사용자에 대한 권한을 검사하게 된다. hasRole을 통해 해당 경로에 접근 가능한 역할을 지정한다.
- UserPrincipal.java
public UserPrincipal(com.hodolog.api.domain.User user) {
super(user.getEmail(), user.getPassword(),
List.of(new SimpleGrantedAuthority("ROLE_ADMIN")
));
this.userId = user.getId();
}
5. 현재 UserPrincipal 클래스에 의해 현재 로그인되는 사용자에 대해서 ADMIN 역할을 부여하게 된다.
- post.http
### 회원가입
POST http://localhost:8080/auth/signup
Content-Type: application/json
{
"name": "백인수",
"email": "saymay10@naver.com",
"password": "1234"
}
### 로그인
POST http://localhost:8080/auth/login
#Content-Type: application/x-www-form-urlencoded
# 폼으로 해당 경로로 POST 요청을 Spring에서 알아서 전달한다.
Content-Type: application/json
{
"email": "saymay10@naver.com",
"password": "1234"
}
### 메인 페이지
GET http://localhost:8080
### 사용자 페이지
GET http://localhost:8080/user
### 관리자 페이지
GET http://localhost:8080/admin
### 게시글 작성
POST http://localhost:8080/posts
Content-Type: application/json
{
"title": "제목입니다.",
"content": "내용입니다."
}
6. SecurityFilterChain에 요청에 대한 역할 부여 코드가 사라진 대신 Controller에 설정하여도 똑같이 요청 경로에 대한 사용자 인증이 똑같이 이루어지는 것을 알 수 있다.
- PostController.java
@PreAuthorize("hasRole('ROLE_USER')")
@PostMapping("/posts")
public void post(@RequestBody @Valid PostCreate request) {
request.validate();
postService.write(request);
}
- 만약 hasRole을 USER로 변환한 다음 (UserPrincipal에 의해 ROLE은 ADMIN으로 설정된다.) /posts 경로로 POST 요청을 하게 되면
현재 사용자의 ROLE은 ADMIN인데 /posts 경로의 허용 역할은 USER이기 때문에 위와 같이 예외가 발생하는 것을 확인 할 수 있다.
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/posts")
public void post(@RequestBody @Valid PostCreate request) {
request.validate();
postService.write(request);
}
- /posts 경로의 허용 역할을 ADMIN으로 바꾸면
- 위와 같이 정상적으로 해당 경로로 접근이 가능한 것을 확인 할 수 있다.
'Programming > Spring' 카테고리의 다른 글
Spring - 페이징, Querydsl RE (0) | 2023.11.14 |
---|---|
Spring - 파일 업로드 Re (0) | 2023.10.17 |
Spring - Spring Security (예외 핸들러 처리, 커스텀 인증 생성) (0) | 2023.10.12 |
Spring - Spring Security (기본 설정, 로그인 폼 커스텀, UserDetailService, 역할 및 권한, remeberMe(자동 로그인)) (0) | 2023.10.10 |
Spring - Signup 비밀번호 암호화 (crypto, SCryptoPasswordEncoder) (1) | 2023.10.09 |