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를 사용하는 경우 매우 유용합니다.


준비사항

  1. OpenResty 또는 Lua 모듈이 포함된 Nginx
  2. Lua 모듈 설치
  3. 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 라이브러리