๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“• Spring Framework/Spring Project

2022.05.24 ใ€Œ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง Ver.2ใ€

by GroovyArea 2022. 5. 24.
์ฃผ๋งˆ๋‹ค ๋ฆฌํŒฉํ„ฐ๋ง ๋ฐ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ํ•˜๋Š” ๋ธŒ๋žœ์น˜๋ฅผ ๋”ฐ ์„ค๊ณ„ํ•˜๋ฉฐ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ ์ค‘์ด๋‹ค. 
์ด๋Ÿฐ ์‹์œผ๋กœ ์ฃผ๋งˆ๋‹ค ๋ฆฌํŒฉํ„ฐ๋ง์„ ํ•˜๋‹ˆ๊นŒ ํ™•์‹คํžˆ ์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•ด์ง€๋Š” ๊ฑธ ๋Š๋‚€๋‹ค.
์˜ค๋Š˜ ์•„์นจ๋ถ€ํ„ฐ ์ง„ํ–‰ํ•œ ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง์€ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋”ฐ์ง€๋Š” ๊ฒƒ์€ ๋ฌผ๋ก ์ด๊ฑฐ๋‹ˆ์™€ ์–ด๋ ค์šด ๋“ฏํ•˜๋ฉด์„œ๋„ ์ƒˆ๋กœ์šด ๊ฐœ๋…์„ ๋„์ž…ํ•ด์„œ ์ง„ํ–‰ํ•˜๋‹ˆ ๋‚˜๋ฆ„ ๋ณด๋žŒ์ฐผ๋˜ ๋ฆฌํŒฉํ„ฐ๋ง์ด์—ˆ๋‹ค. 
์ง๋ฉดํ–ˆ๋˜ ๋ฌธ์ œ๋“ค์„ ๋‚˜์—ดํ•˜๋ฉฐ ์ •๋ฆฌ๋ฅผ ํ•œ๋ฒˆ ํ•ด๋ณด๊ฒ ๋‹ค.

 

์ธ์ฆ & ์ธ๊ฐ€ ์ฑ…์ž„ ๋ถ„๋ฆฌ

๋‚˜๋Š” ์ธ์ฆ, ์ธ๊ฐ€๋ฅผ ์ธํ„ฐ์…‰ํ„ฐ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

์ธ์ฆ์€ ํ† ํฐ ๊ฒ€์ฆ,

์ธ๊ฐ€๋Š” ์—๋„ˆํ…Œ์ด์…˜ ๋ฐ ํ† ํฐ ๊ฒ€์ฆ์œผ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

 

๊ธฐ์กด ์ฝ”๋“œ : ์ธํ„ฐ์…‰ํ„ฐ์˜ preHandle ๋ฉ”์„œ๋“œ ์•ˆ์— ๋‘ ๊ฐœ์˜ ๋กœ์ง์ด ๋™์‹œ์— ๋“ค์–ด์žˆ๋‹ค.

ํ† ํฐ ๊ฒ€์ฆ + ์—๋„ˆํ…Œ์ด์…˜ ๊ฒ€์ฆ

=> ์ฑ…์ž„์ด ๋งŽ๋‹ค -> ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ต๋‹ค.

 

ํ•ด๊ฒฐ : ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ๋‚˜๋ˆ„์–ด ๋ถ„๋ฆฌํ–ˆ๋‹ค.

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    log.info("์ธ์ฆ ์ฒ˜๋ฆฌ ์ธํ„ฐ์…‰ํ„ฐ ์‹คํ–‰");

    /* ํ† ํฐ ์ถ”์ถœ ๋ฐ ๊ฒ€์ฆ */
    String requestToken = authorizationExtractor.extract(request, BEARER_TOKEN);
    jwtTokenProvider.validateToken(requestToken);

    /* ํ† ํฐ body์— ์กด์žฌํ•˜๋Š” ์•„์ด๋””์™€ ๋“ฑ๊ธ‰ */
    final String tokenUserId = jwtTokenProvider.getUserId(requestToken);

    /* request์— ํ† ํฐ ์œ ์ € ๊ถŒํ•œ ์ถ”๊ฐ€ */
    request.setAttribute("tokenUserRole", jwtTokenProvider.getUserGrade(requestToken));

    /* Redis DB์— ์ €์žฅ๋œ ํ† ํฐ ์ถ”์ถœ */
    final ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
    final String redisToken = (String) valueOperations.get(tokenUserId);

    /* DB์— ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ */
    if (redisToken == null) {
        throw new RedisNullTokenException(AuthMessages.NULL_TOKEN.getMessage());
    }

    /* DB ํ† ํฐ๊ณผ ๋กœ๊ทธ์ธ ์œ ์ € ํ† ํฐ ์ •๋ณด๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ */
    if (!redisToken.equals(requestToken)) {
        throw new TokenMismatchException(AuthMessages.INVALID_TOKEN.getMessage());
    }

    return true;
}

=> ์ธ์ฆ ์ฒ˜๋ฆฌ ์ธํ„ฐ์…‰ํ„ฐ

 

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    log.info("๊ถŒํ•œ ์ฒ˜๋ฆฌ ์ธํ„ฐ์…‰ํ„ฐ ์‹คํ–‰");

    if (!(handler instanceof HandlerMethod)) {
        return true;
    }

    /* ํ•ธ๋“ค๋Ÿฌ๋ฉ”์„œ๋“œ ์—๋„ˆํ…Œ์ด์…˜ ๊ฐ’ ์ถ”์ถœ */
    HandlerMethod handlerMethod = (HandlerMethod) handler;
    Auth auth = handlerMethod.getMethodAnnotation(Auth.class);

    /* ๊ถŒํ•œ์ด ํ•„์š” ์—†๋Š” ์ ‘๊ทผ */
    if (auth == null) {
        return true;
    }

    /* ์—๋„ˆํ…Œ์ด์…˜ ๊ฐ’ => ๊ด€๋ฆฌ์ž์ผ ๊ฒฝ์šฐ */
    if (auth.role() == ADMIN) {
        /* ๋กœ๊ทธ์ธ ์œ ์ € ๊ถŒํ•œ์ด ๊ด€๋ฆฌ์ž๊ฐ€ ์•„๋‹ ๊ฒฝ์šฐ */
        if (!request.getAttribute("tokenUserRole").toString().equals(ADMIN.toString())) {
            throw new AuthenticationException(AuthMessages.NOT_ADMIN_AUTH.getMessage());
        }
    }

    return true;
}

=> ๊ถŒํ•œ ์ฒ˜๋ฆฌ ์ธํ„ฐ์…‰ํ„ฐ

 

=> ์ธ์ฆ์ด ์ด๋ฃจ์–ด์ง€๊ณ  ์ธ๊ฐ€๊ฐ€ ์ด๋ฃจ์–ด์ง„๋‹ค. 

 

 

์ค‘๋ณต๋œ ์ฝ”๋“œ & ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง

์žฅ๋ฐ”๊ตฌ๋‹ˆ ๊ด€๋ จ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ค‘๋ณต๋œ ์ฝ”๋“œ๊ฐ€ ๋งŽ์ด ๋ฐœ์ƒํ–ˆ๋‹ค.

์ž‘์„ฑ์„ ๋จผ์ € ํ•˜๊ณ  ๋‚˜์„œ ๋ฆฌํŒฉํ„ฐ๋ง์ด ํ•„์ˆ˜์ ์œผ๋กœ ํ•„์š”ํ•˜๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

๋˜, Service ๊ณ„์ธต์— ๊ด€ํ•ด ๊ถ๊ธˆ์ฆ์ด ์žˆ์—ˆ๋‹ค.

 

๊ธฐ์กด์— ๋‚˜๋Š” Service ๊ณ„์ธต์€ DB ๋กœ์ง์„ ๊ฐ€์ ธ์˜ค๊ณ  ๋„˜๊ฒจ์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค๊ณ  ์•Œ๊ณ  ์žˆ์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ CartController๋Š” ์ฟ ํ‚ค๋กœ ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ Service๋ฅผ ์ด์šฉํ•˜์ง€ ์•Š์•˜๋‹ค. 

ํ•˜์ง€๋งŒ Service๋Š” ์ „๋ฐ˜์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณ„์ธต์œผ๋กœ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์„œ๋น„์Šค๋กœ ๋กœ์ง์„ ์ด๊ด€ํ•ด๋„ ๋˜์—ˆ์—ˆ๋‹ค. 

 

๊ทธ๋Ÿฌ๋‚˜ ์ด๋ฒˆ ๊ฒฝ์šฐ์—๋Š” ๋กœ์ง ์ฒ˜๋ฆฌ ๋ณด๋‹ค๋Š” ์ค‘์ฒฉ๋œ ์ฝ”๋“œ๊ฐ€ ์ฃผ๋œ ๋ฌธ์ œ ์š”์†Œ์˜€๊ธฐ์—, ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ฉ”์„œ๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ํ•ด๊ฒฐํ–ˆ๋‹ค. 

/**
 * ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ฟ ํ‚ค๋ฅผ ๋ฐ˜ํ™˜
 *
 * @param request servlet request ๊ฐ์ฒด
 */
private void getCartCookie(HttpServletRequest request) {
    responseCartCookie = CookieUtil.getCartCookie(request.getCookies()).orElse(null);
}

/**
 * ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ฟ ํ‚ค ๊ฐ’์—์„œ map ๊ฐ์ฒด ์ถ”์ถœ
 *
 * @param responseCookie ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ฟ ํ‚ค
 * @throws UnsupportedEncodingException ์ธ์ฝ”๋”ฉ ๋ฌธ์ œ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ
 */
private void getCartDTOMap(Cookie responseCookie) throws UnsupportedEncodingException {
    cartDTOMap = CookieUtil.getCartItemDTOMap(responseCookie);
}

/**
 * ์žฅ๋ฐ”๊ตฌ๋‹ˆ map ๊ฐ์ฒด์—์„œ ์ƒํ’ˆ ์‚ญ์ œ
 *
 * @param productNo ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ถ”๊ฐ€, ์ˆ˜์ •, ์‚ญ์ œํ•  ์ƒํ’ˆ ๋ฒˆํ˜ธ
 */
private void removeProductFromMap(int productNo) {
    cartDTOMap.remove(productNo);
}

/**
 * ์ „๋‹ฌํ•  ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ฟ ํ‚ค๋ฅผ ์„ธํŒ…
 *
 * @param response servlet response ๊ฐ์ฒด
 * @throws UnsupportedEncodingException ์ธ์ฝ”๋”ฉ ๋ฌธ์ œ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ
 */
private void setCartCookie(HttpServletResponse response) throws UnsupportedEncodingException {
    responseCartCookie.setValue(URLEncoder.encode(JsonUtil.objectToString(cartDTOMap), ENC_TYPE));
    response.addCookie(responseCartCookie);
}

=> ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•œ ๋ฉ”์„œ๋“œ 

 

=> ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์‚ญ์ œ ํ•ธ๋“ค๋Ÿฌ์ด๋‹ค. ํ•œ๋ˆˆ์— ๋ด๋„ ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์œผ๋กœ ์œ ์ถ”๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. 

 

 

For๋ฌธ? Stream? 

๋ฐฐ์—ด์ด๋‚˜ ์ปฌ๋ ‰์…˜์„ ๊ฐ€์ ธ์™€ ๋ฐ˜๋ณต์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊บผ๋‚ด์„œ ๋ณ€๊ฒฝ ๋ฐ ์ถ”์ถœ?

์ด์   ์ด๋ ‡๊ฒŒ ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. 

์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๋„ ๋–จ์–ด์ง€๊ณ , ์œ ์ง€๋ณด์ˆ˜๋„ ์‰ฝ์ง€ ์•Š๋‹ค.

 

=> ์ƒ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚˜๋ฉด? Switch ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•  ๊ฑฐ์•ผ? ์ค„์–ด๋“ค๋ฉด ์ œ๊ฑฐํ•  ๊ฑฐ์•ผ?

 

public static Optional<UserGrade> of(int gradeNumber) {
    return Optional.of(Arrays.stream(UserGrade.values())
            .filter(userGrade1 -> userGrade1.getValue() == gradeNumber)
            .findFirst()
            .orElse(BASIC_USER));
}

=> ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•˜์ž ๊ฐ€๋…์„ฑ์ด ๋งค์šฐ ์ข‹์•„์ง€๊ณ , ๋ณ€๊ฒฝ ์„ฑ๋„ ํ˜„์ €ํžˆ ์ค„์–ด๋“ ๋‹ค. 

 

 

=> ๋”ฑ ๋ด๋„ ํ•„์š” ์—†๋Š” for๋ฌธ์ด ๋Œ์•„๊ฐ€์ง€?

 

@Transactional(readOnly = true)
public List<ProductListDTO> getCategoryList(Map<String, Object> map) {
    return productMapper.selectCategoryList(map).stream()
            .map(productVO -> modelMapper.map(productVO, ProductListDTO.class))
            .collect(Collectors.toList());
}

=> ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•ด์กŒ๋‹ค. 

 

 

๊ฒฐ๋ก 

์ด์ œ ์ฃผ๋ฌธ์ด ๋‚จ์•˜๋‹ค. ์ฃผ๋ฌธ๋„ restFul ํ•˜๊ฒŒ ๋น ๋ฅด๊ฒŒ ์ž‘์„ฑํ•ด๋ณด๊ณ  ๋ถ€์ง€๋Ÿฐํžˆ ํ•ด๋ด์•ผ๊ฒ ๋‹ค.

๋ฆฌํŒฉํ„ฐ๋ง ํ•˜๋ฉด์„œ ์ฝ”๋“œ๊ฐ€ ๊นจ๋—ํ•ด์ง€๋Š” ๊ฑธ ๋ณด๋‹ˆ ํ•  ๋• ์ •๋ง ๋จธ๋ฆฌ์— ์ฅ ๋‚˜์ง€๋งŒ ๋๋‚˜๊ณ  ๋‚˜๋ฉด ์ง„์งœ ๋ฟŒ๋“ฏํ•˜๋‹ค. 

๋” ๋…ธ๋ ฅํ•ด์„œ ๋ฐœ์ „ํ•ด๋ณด์ž~

๋ฐ˜์‘ํ˜•