์คํ๋ง ๋ถํธ ํ๋ก์ ํธ ์ค์ด๋ค. jwt๋ฅผ ์ด์ฉํ ์ธ์ฆ์ ๋ค ๋๋ฌ๊ณ ์ธ๊ฐ ์์ ๋ง ๋จ์๋ค.
๋๋ถ๋ถ ์คํ๋ง ์ํ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํด์ ๊ถํ ์ฒ๋ฆฌ๋ฅผ ํ๋๋ฏํ๋ค. ๋๋ ์ผ๋จ ์ํ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ณ ๋ฏผ์ ์ข ๋ง์ด ํด๋ดค๋ค.
๊ฒฐ๋ก ์ ๋ด๋ฆฌ์๋ฉด ์ธํฐ์ ํฐ๋ฅผ ์ด์ฉํ๊ธฐ๋ก ๊ฒฐ์ฌํ๋ค. ๊ด๋ฆฌ์์ธ์ง ํ์์ธ์ง ์ธ์ฆ์ด ํ์ํ ์์ ์ด๋ ์ง ์ค๋ณต๋๋ ๋ก์ง์ด ๋๋ฌด ๋ง์์ง๋ฏ๋ก ์ด๊ฒ์ ์ธํฐ์ ํฐ์์ ์ปจํธ๋กค๋ฌ๋ก ๋์ด๊ฐ๊ธฐ ์ ์ ์ธ๊ฐ ์์ ์ ํด์ค์ผ ํ๋ ๊ฒ์ด ์ฃผ๋ ์ด์ ๋ค.
ํ๋ฒ ํด๋ณด์~
=> ์ ๋ฐ์ ์ธ ๊ณํ ์์ฑ
์ค๊ฐ ์ ๋ฆฌ
ํผ์ ํ๋ก์ ํธ๋ฅผ ํด์ ์ธ์ง ์๋๊ฐ ๋๋ฌด ๋์ง ์๋๋ค.
์๊ฐ์ ํด๋ณด์๋ค.
์ด๋ ํ ๊ธฐ๋ฅ์ด๋ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ๊ฒ ์ค๊ณํ๊ธฐ ๋๋ฌธ์ด๋ผ๋ ์๊ฐ์ด ๋ค์๋ค. ๊ฐ์ฅ ์๊ฐ์ ๋ง์ด ์์ ๋ถ๋ถ์ Restful ํ ์ค๊ณ ๋ฐฉ์๊ณผ ์ธ์ฆ ์ธ๊ฐ ๋ถ๋ถ์ด๋ค. ์ด์ ๊ฒจ์ฐ ๋๋ธ ๊ฒ ๊ฐ๋ค. JWT๋ฅผ ์ด์ฉํด Redis๋ฅผ ์ ์ฉ์ํค๋ ์ด๊ฒ ์๊ทผํ ๊ฐ๋จํ์ง๋ง์ ์๋ค.
๋ฌธ์ ์
1. RestFul ํ ์๋ต
-> ๋จ์ํ ResponseEntity๋ฅผ ์ฌ์ฉํด ์๋ต ์ฝ๋, ๋ฐ์ดํฐ, ํ์ ๋ฑ์ ๋ณด๋ด๋ฉด ๋์ง ์๋ ์๊ฐ์ ํ์๋ค.
ํด๋ผ์ด์ธํธ ๋จ ์๊ตฌ ํ์์ ๋ฐ๋ผ ์๋ต์ ์ ์ฐํ๊ฒ ๋ฌ๋ผ์ง ์ ์๋ค๋ ์ ์ ๋ฐฐ์ ๋ค.
์๋ฅผ ๋ค์ด ์์ธ ๋ฉ์์ง๋ง ๋ณด๋ผ ๊ฒฝ์ฐ, ๊ตณ์ด ๋ฐ์ดํฐ ํ์๊น์ง๋ ๋ณด๋ผ ํ์๊ฐ ์๋ค.
2. ์ธํฐ์ ํฐ์ ํํฐ
-> ๊ถํ ์ฒ๋ฆฌ์์ ํ์์ ์ธ ์กด์ฌ๋ค์ด๋ค.
์คํ๋ง ๊ฐ๊ตฌ๋ฆฌ ์ฑ ์์ ๋ดค๋ฏ์ด ์คํ๋ง์ ์ ๋ง ํ๋ฉด ํ ์๋ก ์๋ฒฝํ ๊ฐ์ฒด์งํฅ๊ณผ ๋์์ธ ํจํด์ ๋ฐ๋ฅด๊ณ ์๋ค๋ ๊ฒ์ ์์๊ฐ๋ค.
์ธ์ฆ ์ฒ๋ฆฌ๋ ๋ณดํต ๊ฐ์ฅ ๋๋ต์ ์ธ ๊ฒ์ฆ์ด๋ฏ๋ก ํธ๋ค๋ฌ ์ง์ ์ด ์๋๋ผ ๋์ค ํจ์ณ ์๋ธ๋ฆฟ์ด ๋ฐ๊ธฐ ์ ์ฒ๋ฆฌํด์ฃผ๋ ๊ฒ ๋ง๋ค.
์ํ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๊ตฌํํ๋ค๋ณด๋ ํํฐ์์ ๋ฐ์์ํจ ์์ธ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ถ๋ถ์์ ๊ณ ๋ฐฐ๋ฅผ ๋ง์ จ๋ค.
๋๋ ์ธํฐ์ ํฐ๋ฅผ ์ด์ฉํ์ฌ ์ธ์ฆ, ๊ถํ ์ฒ๋ฆฌ๋ฅผ ํ๋ค.
public class JwtRequestFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(JwtRequestFilter.class);
private final AuthorizationExtractor authorizationExtractor;
private final JwtTokenProvider jwtTokenProvider;
public JwtRequestFilter(AuthorizationExtractor authorizationExtractor, JwtTokenProvider jwtTokenProvider) {
this.authorizationExtractor = authorizationExtractor;
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = authorizationExtractor.extract(request, "Bearer");
try {
jwtTokenProvider.validateToken(token);
} catch (ExpiredJwtException e) {
logger.error("Expired Jwt token : {}", e.getMessage());
setErrorResponse(response, "Expired Jwt token");
} catch (UnsupportedJwtException e) {
logger.error("Unsupported JWT token : {}", e.getMessage());
setErrorResponse(response, "Unsupported JWT token");
} catch (MalformedJwtException e) {
logger.error("Invalid JWT token : {}", e.getMessage());
setErrorResponse(response, "Invalid JWT token");
} catch (SignatureException e) {
logger.error("Invalid JWT token signature : {}", e.getMessage());
setErrorResponse(response, "Invalid JWT token signature");
} catch (IllegalArgumentException e) {
logger.error("JWT claims string is empty : {}", e.getMessage());
setErrorResponse(response, "JWT claims string is empty");
} catch (ClassCastException e) {
logger.error("JWT claims inspect fail : {}", e.getMessage());
setErrorResponse(response, "JWT claims inspect fail");
}
}
private void setErrorResponse(HttpServletResponse response, String message) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
response.setCharacterEncoding("utf-8");
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write(objectMapper.writeValueAsString(new Message.Builder("null")
.httpStatus(HttpStatus.UNAUTHORIZED)
.message(message)
.build())
);
}
}
=> ๊ฒฐ๊ตญ ์ฌ์ฉํ์ง ์์์ง๋ง ์ฒ์ฐธํ ํ์ ๋ค..
๋ชจ๋ ์์ฒญ์ ๋ํ ์ธํฐ์ ํฐ๋ฅผ ๋ฑ๋กํ๊ณ ,
/**
* ๊ถํ ์ฒ๋ฆฌ ์ธํฐ์
ํฐ <br>
* ํ ํฐ ๊ฒ์ฆ ๋ฐ ์๋ํ
์ด์
๊ถํ ์ฒ๋ฆฌ๋ฅผ ์คํํ๋ค.
*
* <pre>
* <b>History</b>
* ์์ฑ์, 1.0, 2022.05.20 ์ต์ด ์์ฑ
* </pre>
*
* @author ๊น๋จ์
* @version 1.0
*/
@Component
public class AuthInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(AuthInterceptor.class);
private static final String BEARER_TOKEN = "Bearer";
private final AuthorizationExtractor authorizationExtractor;
private final JwtTokenProvider jwtTokenProvider;
private final RedisTemplate<String, String> redisTemplate;
public AuthInterceptor(AuthorizationExtractor authorizationExtractor, JwtTokenProvider jwtTokenProvider, RedisTemplate<String, String> redisTemplate) {
this.authorizationExtractor = authorizationExtractor;
this.jwtTokenProvider = jwtTokenProvider;
this.redisTemplate = redisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
/* ํธ๋ค๋ฌ๋ฉ์๋ ์๋ํ
์ด์
๊ฐ ์ถ์ถ */
HandlerMethod handlerMethod = (HandlerMethod) handler;
Auth auth = handlerMethod.getMethodAnnotation(Auth.class);
if (auth == null) {
return true;
}
/* ํ ํฐ ์ถ์ถ ๋ฐ ๊ฒ์ฆ */
String requestToken = authorizationExtractor.extract(request, BEARER_TOKEN);
jwtTokenProvider.validateToken(requestToken);
/* ํ ํฐ body์ ์กด์ฌํ๋ ์์ด๋์ ๋ฑ๊ธ */
final String tokenUserId = jwtTokenProvider.getUserId(requestToken);
final String tokenUserRole = jwtTokenProvider.getUserGrade(requestToken);
/* Redis DB์ ์ ์ฅ๋ ํ ํฐ ์ถ์ถ */
final ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
final String redisToken = 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());
}
/* ์๋ํ
์ด์
๊ฐ => ๊ด๋ฆฌ์์ผ ๊ฒฝ์ฐ */
if (auth.role() == ADMIN) {
/* ๋ก๊ทธ์ธ ์ ์ ๊ถํ์ด ๊ด๋ฆฌ์๊ฐ ์๋ ๊ฒฝ์ฐ */
if (!tokenUserRole.equals(ADMIN.toString())) {
throw new AuthenticationException(AuthMessages.NOT_ADMIN_AUTH.getMessage());
}
}
return true;
}
}
ํ ํฐ๊ณผ ์๋ํ ์ด์ ๊น์ง ๋น๊ตํ๋ค.
๊ถํ ์๋ํ ์ด์ ์ ์
์ด๋ฐ ์์ผ๋ก ํธ๋ค๋ฌ ๋ฉ์๋์ ์๋ํ ์ด์ ์ ์ถ๊ฐํ์ฌ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
์ ๋๋ค์! ๋ณธ ๋ก๊ทธ์ธ ์ฌ์ฉ์๋ ์ผ๋ฐ ๋ฉค๋ฒ ๋ฑ๊ธ์.
๋ด๊ฐ ๊ถํ ์ฒ๋ฆฌ์์ ์๋ํ ์ด์ ์ ์ฌ์ฉํ ์ด์
ํ๋ก์ ํธ ํฌ๊ธฐ ๋จ์๋ก ๋ณด์์ ๋ ๊ท๋ชจ๊ฐ ์ปค์ง ๊ฒฝ์ฐ ์ฝ๋๋ฅผ ๊ณต์ ํ๊ฒ ๋ ํ ๋ฐ ์ด๋ ์๋ํ ์ด์ ์ ์ด์ฉํ์ฌ ๋ช ์์ ์ธ ๊ถํ์ ํ์๋ค์ด ์ ์ ์๋ค๋ ์๊ฐ์ ํ๋ค.
์ด์ ๋จ์ ๊ฒ์ ์ฅ๋ฐ๊ตฌ๋์ ์ฃผ๋ฌธ์ด๋ค. ์ ๋๋ก ํด๋ณด์
'๐ Spring Framework > Spring Project' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
2022.05.22 ใShopping Cart API [Ver.2]ใ (0) | 2022.05.22 |
---|---|
2022.05.21 ใ Shopping Cart API ๋ง๋ค๊ธฐ ใ (0) | 2022.05.21 |
2022.05.18 ใRedis DB ์ ์ฉใ (0) | 2022.05.18 |
2022.05.16 ใ๋ฆฌํฉํ ๋งใ (0) | 2022.05.16 |
2022.05.14 ใJWT ์ธ์ฆใ (0) | 2022.05.14 |