Spring

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

BigBeen 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๋‹จ์—์„œ ์ข…๋ฃŒ๋˜๋ฒ„๋ฆฌ๋Š” ์—๋Ÿฌ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž ์ •์˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋‚ด๋ ค์ค„ ์ˆ˜ ์—†์„๋•Œ
์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•