Nginx
[Nginx] Lua로 JWT 인증 처리하기 – API Gateway에 인증 붙이기 feat. Lua 와 JWT로 사용자 정보 받아오기
임혁진
2025. 4. 19. 08:08
왜 Lua + Nginx로 인증을 처리할까?
보통 JWT 인증은 백엔드(Spring 등) 에서 처리하지만,
Nginx에서 요청을 받기 전에 인증을 미리 처리하면:
- ✅ 불필요한 부하 감소
- 인증 실패 요청을 사전에 차단
- ✅ 보안 향상
- API Gateway에서 인증을 처리하므로, 각 서비스에서 인증 로직 중복을 줄여 백엔드 로직을 간단하게 유지
- ✅ API Gateway 성능 최적화 가능
특히 마이크로서비스에서 API Gateway를 사용하는 경우 매우 유용합니다.
준비사항
- OpenResty 또는 Lua 모듈이 포함된 Nginx
- Lua 모듈 설치
- resty.jwt Lua 라이브러리
luarocks install lua-resty-jwt
Nginx + Lua JWT 인증 흐름
단계 | 설명 |
1. Spring Boot 서버에서 JWT 발급 (인증) |
사용자가 로그인하면 Spring Boot 서버에서 JWT 토큰을 생성하여 응답으로 전달합니다. 이때 토큰은 서명(보통 HS256, RS256 등)되어 있어야 해요. |
2. Nginx + Lua에서 JWT 검증 (인가) |
클라이언트가 이후 요청마다 JWT를 Authorization 헤더에 담아 보내면, 이 요청을 Nginx가 가로채고 Lua 스크립트를 통해 토큰 유효성(JWT 서명, 만료 등)을 확인합니다. |
3. 검증 통과 시 백엔드로 전달 | 토큰이 유효하면 Nginx가 요청을 백엔드(Spring Boot)로 프록시합니다. 그렇지 않으면 401 Unauthorized 응답을 줍니다. |
설정 예시: nginx.conf
http {
lua_shared_dict jwt_cache 10m;
server {
listen 80;
location /api/ {
access_by_lua_block {
local jwt = require "resty.jwt"
-- 1. 헤더에서 JWT 추출
local auth_header = ngx.var.http_Authorization
if not auth_header then
ngx.status = 401
ngx.say("401 Unauthorized - Missing Authorization header")
return ngx.exit(401)
end
local _, _, token = string.find(auth_header, "Bearer%s+(.+)")
if not token then
ngx.status = 401
ngx.say("401 Unauthorized - Invalid token format")
return ngx.exit(401)
end
-- 2. JWT 검증
local jwt_obj = jwt:verify("secret-key", token)
if not jwt_obj.verified then
ngx.status = 401
ngx.say("401 Unauthorized - Invalid token")
return ngx.exit(401)
end
-- 3. 원하는 클레임 로그 (옵션)
ngx.log(ngx.INFO, "User ID: ", jwt_obj.payload.sub)
}
proxy_pass http://backend_service;
}
}
}
access_by_lua_block 대신
access_by_lua_file /etc/nginx/lua/jwt.lua;
로 lua 파일을 따로 지정할 수도 있다.
JWT 서명 키와 알고리즘
기본적으로 HMAC 방식 (HS256)을 사용하며,
키는 "secret-key" 부분에 지정해줘야 합니다.
만약 RSA (RS256) 방식이라면 public key 파일을 불러와야 합니다.
테스트 방법 (curl 사용)
curl -H "Authorization: Bearer <JWT>" http://ec2-public-ip/api/
※JWT로 사용자 정보 받아오기
jwt_obj.payload에서 사용자 정보 추출 예시
JWT 토큰 payload는 일반적으로 아래와 같은 JSON 구조를 가집니다:
{
"sub": "user123",
"role": "USER",
"exp": 1713172800
}
Lua에서는 이렇게 추출할 수 있습니다.
local user_id = jwt_obj.payload.sub
local role = jwt_obj.payload.role
-- 예: 백엔드에 사용자 정보를 전달할 수 있음
ngx.req.set_header("X-User-Id", user_id)
ngx.req.set_header("X-User-Role", role)
이렇게 하면 백엔드(Spring 등)는 JWT를 직접 파싱하지 않아도 X-User-Id, X-User-Role 헤더로 사용자 정보를 받을 수 있습니다.
정리
- Lua + Nginx으로 API Gateway에서 인증 미리 처리
- 백엔드 서버는 오직 로직만 담당 → MSA에 이상적
- 캐시, 리미팅, 인증까지 모두 전처리 가능
- resty.jwt는 가장 많이 사용되는 Lua JWT 라이브러리