ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Security + JWT ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ (3)
    Spring 2022. 10. 23. 17:11
    ๋ฐ˜์‘ํ˜•

    ๐Ÿ’ก ์ง€๋‚œ ํฌ์ŠคํŠธ์— ์ด์–ด์„œ Security์˜ 403 Forbidden ์—๋Ÿฌ๋ฅผ ํ•ธ๋“ค๋ง ํ•˜๋Š” Class๋ฅผ
    ์„ค์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


    ์ด์ „ ํฌ์ŠคํŒ…์€ ํ•ด๋‹น ๋งํฌ๋ฅผ ์ฐธ์กฐ ํ•ด์ฃผ์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.
    https://developer-been.tistory.com/3

     

    Spring Security + JWT ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ (2)

    ๐ŸŽˆ ์ง€๋‚œ ๊ฒŒ์‹œ๊ธ€์—์„  Spring Security์˜ ๊ตฌ์กฐ์™€ ํ•„์š”ํ•œ Settings์„ ๋‹ค๋ค˜์Šต๋‹ˆ๋‹ค. ์ด์–ด์„œ Security์— ํ•„์š”ํ•œ Class๋“ค์„ ๋‹ค๋ค„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ง€๋‚œ ํฌ์ŠคํŒ…์€ ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ์กฐ ํ•˜์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค. https://developer-been.ti

    developer-been.tistory.com



    Spring Security
    AccessDeniedHandler์ธํ„ฐํŽ˜์ด์Šค์™€ AuthenticationEntryPoint์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

    ๐Ÿ’ก AccessDeniedHandler
    ์„œ๋ฒ„์— ์š”์ฒญ์„ ํ•  ๋•Œ ์•ก์„ธ์Šค๊ฐ€ ๊ฐ€๋Šฅํ•œ์ง€ ๊ถŒํ•œ์„ ์ฒดํฌํ›„ ์•ก์„ธ์Šค ํ•  ์ˆ˜ ์—†๋Š” ์š”์ฒญ์„ ํ–ˆ์„์‹œ ๋™์ž‘ ๋ฉ๋‹ˆ๋‹ค.

    ๐Ÿ’ก AuthenticationEntryPoint
    ์ธ์ฆ ๋˜์ง€์•Š์€ ์œ ์ €๊ฐ€ ์š”์ฒญ์„ ํ–ˆ์„๋•Œ ๋™์ž‘ ๋ฉ๋‹ˆ๋‹ค.

     

    ๐Ÿ’ก ๊ตฌํ˜„ํ•˜๋Š” ์ด์œ  ?

    ํ˜„์žฌ Filter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Servlet๋‹จ์—์„œ ๊ฒ€์ฆ์„ ํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์ด ๋•Œ
    1๏ธโƒฃ ๊ถŒํ•œ์ด ์—†๋Š” ์•ก์„ธ์Šค ์š”์ฒญ 2๏ธโƒฃ ์ธ์ฆ์ด ๋˜์ง€ ์•Š์€ ์š”์ฒญ
    ๋‘ ๊ฐ€์ง€ ๊ฒฝ์šฐ ๋ชจ๋‘ 403 forbidden ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
    ์ด ๊ฒฝ์šฐ์— DispatcherServlet๋‹จ๊นŒ์ง€ ๋‹ฟ์„ ์ˆ˜๊ฐ€ ์—†๊ณ , Servlet๋‹จ์—์„œ ์ข…๋ฃŒ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
    ์ด๋Ÿฐ ์ƒํ™ฉ์— ์‚ฌ์šฉ์ž ์ •์˜ ์—๋Ÿฌ ํ•ธ๋“ค๋ง์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

     

     

    ๐Ÿ’ก ์‚ฌ์šฉ๋ฐฉ๋ฒ•
    (1)๋ฒˆ ๊ธ€์—์„œ WebSecurityConfig์— ์„ค์ •ํ•œ ๋Œ€๋กœ ํด๋ž˜์Šค๋“ค์„ ๋ช…์‹œ ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    .and()
       .exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint)
       .accessDeniedHandler(customAccessDeniedHandler)

     

     

    ๐Ÿ“Œ CustomAccessDeniedHandler Calss ์ƒ์„ฑ

    @Component
    @Slf4j
    public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    
        @Override
        public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
    
            log.error("Forbidden : ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.");
    
            httpServletResponse.setContentType("application/json; charset=UTF-8");
            httpServletResponse.setStatus(HttpStatus.OK.value());
    
            try (OutputStream os = httpServletResponse.getOutputStream()){
    
                BaseResDto baseResDto = new BaseResDto();
                baseResDto.setResultCode(ResultCode.ACCESS_NO_AUTH.getResultCode());
                baseResDto.setResultMessage(ResultCode.ACCESS_NO_AUTH.getResultMessage());
    
                ObjectMapper objectMapper = new ObjectMapper();
                objectMapper.writeValue(os, baseResDto);
                os.flush();
            }
        }
    }
    • 403 forbidden ์—๋Ÿฌ (AccessDeniedException) ๋ฐœ์ƒ์‹œ, AccessDeniedHandler๋ฅผ ๊ตฌํ˜„ํ•œ ํ•ด๋‹น Customํด๋ž˜์Šค๋กœ ์ง„์ž…์„ ํ•ฉ๋‹ˆ๋‹ค.
    • ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋ฅผ ๋‚ด๋ ค์ฃผ๊ธฐ ์œ„ํ•ด์„œ json type, status code 200์œผ๋กœ ์„ค์ •์„ ํ•ด์ค๋‹ˆ๋‹ค.
    • ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์‚ฌ์šฉ์ž ์ •์˜ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ Set ํ•ฉ๋‹ˆ๋‹ค.
    • ObjectMapper๋ฅผ ์ด์šฉํ•˜์—ฌ writeํ•˜๊ณ  flush ํ•˜๋ฉด Status 200 ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋ฅผ Json ํ˜•ํƒœ๋กœ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ๐Ÿ“Œ CustomAuthenticationEntryPoint Calss ์ƒ์„ฑ

     

    ๐Ÿ’ก Jwt ๊ฒ€์ฆ์‹œ ๋ฐœ์ƒํ•˜๋Š” Exception์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธฐ ์œ„ํ•ด AuthenticationEntryPoint๋ฅผ ๊ตฌํ˜„ํ•œ EntryPoint ์ž…๋‹ˆ๋‹ค.
    ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ 403 forbidden Error๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , Servlet๋‹จ์—์„œ ์ข…๋ฃŒ๋˜๊ธฐ ๋•Œ๋ฌธ์—
    ์‚ฌ์šฉ์ž ์ •์˜ ์—๋Ÿฌ ํ•ธ๋“ค๋ง์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    @Component
    public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
    
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
            BaseResDto baseResDto = new BaseResDto();
            String exceptionType = (String) request.getAttribute("exception");
    
            if (exceptionType.equals("invalidSignature")) {
                baseResDto.setResultCode(ResultCode.SIGNATURE_EXCEPTION.getResultCode());
                baseResDto.setResultMessage(ResultCode.SIGNATURE_EXCEPTION.getResultMessage());
            } else if (exceptionType.equals("invalidJwt")) {
                baseResDto.setResultCode(ResultCode.MALFORMED_JWT_EXCEPTION.getResultCode());
                baseResDto.setResultMessage(ResultCode.MALFORMED_JWT_EXCEPTION.getResultMessage());
            } else if (exceptionType.equals("expiredJwt")) {
                baseResDto.setResultCode(ResultCode.ACCESS_TOKEN_EXPIRED.getResultCode());
                baseResDto.setResultMessage(ResultCode.ACCESS_TOKEN_EXPIRED.getResultMessage());
            } else if (exceptionType.equals("claimsEmpty")) {
                baseResDto.setResultCode(ResultCode.ILLEGAL_ARGUMENT_EXCEPTION.getResultCode());
                baseResDto.setResultMessage(ResultCode.ILLEGAL_ARGUMENT_EXCEPTION.getResultMessage());
            } else {
                baseResDto.setResultCode(ResultCode.UNSUPPORTED_JWT_EXCEPTION.getResultCode());
                baseResDto.setResultMessage(ResultCode.UNSUPPORTED_JWT_EXCEPTION.getResultMessage());
            }
    
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("resultCode", baseResDto.getResultCode());
            jsonObject.put("resultMessage", baseResDto.getResultMessage());
    
            response.setStatus(HttpStatus.OK.value());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().print(jsonObject);
            response.getWriter().flush();
        }
    }

    ์•ž์„œ ๊ตฌํ˜„ํ•œ JwtTokenProvider.class์˜ validateToken() ํ•จ์ˆ˜์—์„œ Jwt ๊ด€๋ จ Exception์„ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ ํ–ˆ์Šต๋‹ˆ๋‹ค.

     

    ๊ณผ์ •์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    1๏ธโƒฃ ๊ฐ Exception๋งˆ๋‹ค HttpServletRequest์— Attribute๋ฅผ set ํ•ด์ค€ ์ƒํƒœ์—์„œ, EntryPoint๋กœ ๋„˜์–ด์˜ต๋‹ˆ๋‹ค.
    2๏ธโƒฃ EntryPoint์—์„œ Attribute๋ฅผ get ํ•ด์„œ ์‚ฌ์šฉ์ž ์ •์˜ String์„ ํ™•์ธ ํ•œ ํ›„์—, ํ•ด๋‹น Exception์— ๋งž๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋ฅผ Set ํ•ด์ค๋‹ˆ๋‹ค.
    3๏ธโƒฃ JSONObject์— ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋ฅผ Put ํ•œ ๋’ค, HttpServletResponse์— json type๊ณผ status 200 Code๋ฅผ Set ํ•ฉ๋‹ˆ๋‹ค.
    4๏ธโƒฃ HttpServletResponse์˜ getWriter().print() ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด json ๋ฌธ์ž์—ด์„ ์ถœ๋ ฅํ•˜๊ณ , ์ตœ์ข…์ ์œผ๋กœ flush()๋ฅผ ํ†ตํ•ด ๋น„์›Œ์ค๋‹ˆ๋‹ค.

     

     

    ์ด๋ ‡๊ฒŒ 403 forbidden ์—๋Ÿฌ๋ฅผ ํ•ธ๋“ค๋ง ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค.
    Servlet๋‹จ์—์„œ ์ข…๋ฃŒ๋˜๋ฒ„๋ฆฌ๋Š” ์—๋Ÿฌ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž ์ •์˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋‚ด๋ ค์ค„ ์ˆ˜ ์—†์„๋•Œ
    ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.

    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€

Designed by Tistory.