SpringBoot [스프링부트] Spring Security Baisc (3)
전 글에서 인증과 권한에 대해 다뤘고, 같은 권한을 가진 User는 다른 User의 리소스에 접근할 수 있었습니다. Interceptor를 통해서 인가 문제를 해결해보겠습니다.
1. Interceptor란?
인터셉터(Interceptor)는 스프링의 Spring Context(ApplicationContext) 기능입니다.
임의의 URI를 호출 시 DispatcherServlet에서 해당 Controller가 처리되기 전과 후에 발생하는 것을 처리할 수 있습니다.
즉 DispatcherServlet -> Interceptor -> Controller -> Interceptor -> ~~ 로 표현할 수 있습니다.
2. UserController 수정
@PostMapping("/character")
public String create(@RequestParam(name = "name") String name,
HttpServletRequest request){
HttpSession session = request.getSession(false);
String email = (String) session.getAttribute("email");
Character character = userService.createCharacter(name, email);
return "ok";
}
- 더 이상 로그인을 한 User에게서는 RequestParam으로 User 정보를 받지 않고, 인증을 성공한 User에 한해서 CustomLoginSuccessHandler에서 session을 만들고 정보를 넣습니다. 이제 Controller에서는 HttpServlerRequest에서 session을 꺼내 어떠한 User인지 알 수 있습니다.
3. CustomLoginSuccessHandler 수정
public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
SecurityContextHolder.getContext().setAuthentication(authentication);
String email = authentication.getName();
HttpSession session = request.getSession();
session.setAttribute("email",email);
response.sendRedirect("/success");
}
}
- Authentication.getName()을 통해서 User의 email을 꺼내고 session을 성성하고 정보를 넣습니다.
session과 코드의 중복을 줄이는 ArgumentResolver를 알아보고 싶으시면 아래 링크들에서 확인 부탁드립니다:)
SpringBoot [스프링부트] 시작하기(6) MemberController 만들기
UserController를 만들었던 거 처럼 MemberController를 만들겠습니다. 1. MemberController Controller위에 @RequestMapping("member")을 주면 모든 메소드에 적용됩니다. /member/~~이런식으로 식별됩니다. @Pos..
dingdingmin-back-end-developer.tistory.com
SpringBoot [스프링부트] 시작하기(7) ArgumentResolver 만들기
전 시간에 Controller에서 Session을 가져오는 데 있어서 중복 코드가 있었습니다. 해당 코드를 ArgumentResolver로 해결해보겠습니다. ArgumentResolver란? 컨트롤러의 메소드의 인자로 사용자가 임의의 값을
dingdingmin-back-end-developer.tistory.com
4. CharacterRepository 수정 (fetch join을 추가해줍니다.)
public interface CharacterRepository extends JpaRepository<Character, Long> {
@Query("select c from Character c join fetch c.user where c.id= :id")
Optional<Character> findFetchById(@Param("id") Long id);
}
5. CharacterInterceptor추가 (주석을 통한 설명)
@RequiredArgsConstructor
@Component
public class CharacterInterceptor implements HandlerInterceptor {
private final CharacterRepository characterRepository;
//Filter 에서 이미 권한에 관한 것을 처리했으므로 인가에 관해서만 처리합니다.
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// URI 즉 localhost:8080의 그 뒷부분이 해당합니다.
String requestURI = request.getRequestURI();
//session 을 통해서 어느 User 가 요청했는지 알 수 있습니다.
String email = (String) request.getSession().getAttribute("email");
//Post 에 관해서는 자신의 캐릭터를 만드는 것이므로 모두 접근 가능하지만 Patch 에 관해서는 자신이 소유한 것만 가능하므로 체크해줍니다.
if(requestURI.contains("/character") && request.getMethod().equals("PATCH")){
//Patch 를 하는 캐릭터의 id 입니다.
long id = Long.parseLong(request.getParameter("id"));
Character character = characterRepository.findFetchById(id).get();
if(!character.getUser().getEmail().equals(email)){
// 인가 되지 않으므로 /notAccess 로 redirect합니다.
response.sendRedirect("/notAccess");
// false 일 경우 원래 접근하고자 하는 uri에 요청을 보내지 않습니다.
// return false를 해주지 않으면 밑에 로직들이 실행되므로 반드시 해줘야합니다.
return false;
}
}
else{
return true;
}
// return true 이므로 자원에 접근할 수 있습니다.
return true;
}
}
6. WebConfig 추가
@EnableWebMvc
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final CharacterRepository characterRepository;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CharacterInterceptor(characterRepository))
.addPathPatterns("/character") // "/character"에 대해서만 Interceptor를 적용합니다.
.excludePathPatterns("/signup","/login","/notAccess","/user","/guest","/"); // 적어준 uri에 대해선 Interceptor를 적용하지 않습니다.
}
}
7. Postman test
- asdf User와 qwer User가 가입을 합니다.
- asdf User가 로그인을 한 후 Character를 만듭니다.
- asdf User는 Character의 이름을 업데이트가 가능합니다.
- qwer User가 로그인을 한 후 asdf User가 만든 Character에 대해서 인가가 되어 수정이 가능한지 보겠습니다.
- 수정이 불가능한 것을 볼 수 있습니다.
지금까지 Security의 Filter를 직접 만들어 권한과 인증처리를 완료했고, Interceptor를 통해서 인가에 대한 처리를 완료했습니다. Security에 전반적인 부분을 살펴보았습니다. 감사합니다.
모든 코드는 아래 링크에서 확인 가능합니다.
https://github.com/rlaehdals/secuitybasic
GitHub - rlaehdals/secuitybasic
Contribute to rlaehdals/secuitybasic development by creating an account on GitHub.
github.com
'SpringBoot > spring security' 카테고리의 다른 글
Springboot[스프링부트] Spring Security Basic(5) 동작 과정 (0) | 2022.05.13 |
---|---|
Springboot [스프링부트] Spring Sercurity Basic(4) (0) | 2022.02.12 |
SpringBoot [스프링부트] Spring Security Basic(2) (0) | 2022.01.27 |
SpringBoot [스프링 부트] Spring Security Basic (1) 프로젝트 생성 (0) | 2022.01.25 |
SpringBoot [스프링부트] Spring Security Basic (0) (0) | 2022.01.25 |
댓글
이 글 공유하기
다른 글
-
Springboot[스프링부트] Spring Security Basic(5) 동작 과정
Springboot[스프링부트] Spring Security Basic(5) 동작 과정
2022.05.13 -
Springboot [스프링부트] Spring Sercurity Basic(4)
Springboot [스프링부트] Spring Sercurity Basic(4)
2022.02.12 -
SpringBoot [스프링부트] Spring Security Basic(2)
SpringBoot [스프링부트] Spring Security Basic(2)
2022.01.27 -
SpringBoot [스프링 부트] Spring Security Basic (1) 프로젝트 생성
SpringBoot [스프링 부트] Spring Security Basic (1) 프로젝트 생성
2022.01.25