H3C SecPath ACG 1000 시리즈 인터넷 행동 관리와 Feishu OAuth2.0 기업 인증 통합 구축 실무

본 문서는 실제 기업 운영 환경에서의 구축 사례를 기반으로, H3C SecPath ACG 1000 시리즈 인터넷 행동 관리 장비가 미들웨어 서버(172.20.10.1)를 통해 Feishu(飞书) 오픈 플랫폼의 OAuth2.0과 연동하여 직원이 Feishu QR 코드 스캔만으로 인증 및 네트워크에 접속할 수 있는 전체 과정을 상세히 기록합니다. 실제 설정, 운영 수준 코드, 상호 작용 시퀀스, 필드 매핑, 문제 해결, 운영 최적화를 포함하여 기술 공유 및 현장 구축에 직접 활용할 수 있습니다.

서론

기업 내부 네트워크 무선 인증은 기존의 아이디/비밀번호 방식을 대체하여 Feishu 계정으로 한 번에 인증할 수 있어야 합니다. 그러나 H3C 장비와 Feishu 오픈 플랫폼 간에는 인터페이스 형식, JSON 구조, 매개변수 규격이 호환되지 않아 직접 연결이 불가능합니다. 본 문서에서는 경량 비동기 미들웨어(FastAPI + httpx)를 사용하여 프로토콜을 변환하고 필드를 매핑함으로써 안정적이고 효율적이며 추적 가능한 엔터프라이즈급 무선 인증 솔루션을 구현합니다.

1. 핵심 배경 및 제약 조건

1.1 비즈니스 요구 사항

  • 최종 사용자가 기업 네트워크에 연결 → H3C OAuth 인증 트리거 → 미들웨어 서버(Windows 또는 Linux 가능) → Feishu QR 코드 승인 → 자동 네트워크 접속
  • 인증 로그의 로컬 저장, 높은 동시성 처리, 메모리 안정성, 콘솔 출력 깨짐 방지

1.2 핵심 기술적 제약

  • H3C 인터넷 행동 관리: OAuth2.0 인가 코드 모드만 지원하며, 평면 JSON 반환(usercode/username/userorg)만 인식하고 최상위 필드만 처리 가능
  • Feishu 오픈 플랫폼: 중첩된 JSON을 고정적으로 반환하며, 인터페이스 매개변수, 권한, 토큰 전달에 엄격한 규칙 존재
  • 네트워크 환경: 비동기 미들웨어 서버 고정 IP 172.20.10.1, H3C 장비 브리지 IP 172.20.0.2(대역 외 관리 주소 아님)

1.3 솔루션 선택

  • 직접 연결: H3C ↔ Feishu (형식 불일치로 사용자 이름 확인 불가)
  • 미들웨어 방식: H3C ↔ 비동기 미들웨어 ↔ Feishu (프로토콜 변환, 필드 평탄화, 안정성 강화)

2. 전체 아키텍처

2.1 핵심 구성 요소

  • H3C 인터넷 행동 관리: OAuth2.0 클라이언트, 인증 진입점 및 정책 제어
  • 비동기 미들웨어 (172.20.10.1): FastAPI + httpx 기반 중계 서비스, H3C와 Feishu 간 프로토콜 변환, 필드 매핑, 캐싱, 로깅 등 모든 기능 담당
  • Feishu 오픈 플랫폼: 기업 사용자 정보 소스, OAuth2.0 인가 및 사용자 정보 조회 제공

2.2 배포 정보

  • 비동기 미들웨어 서버: 172.20.10.1:8000
  • H3C 장비 콜백 주소: http://172.20.0.2:8000/
  • Feishu 앱: 기업 자체 구축 앱

3. OAuth2.0 전체 상호 작용 흐름

(상호 작용 흐름도는 H3C, 미들웨어, Feishu 간의 OAuth2.0 인가 코드 모드 과정을 보여줍니다.)

4. 플랫폼별 핵심 설정 (실제 설정)

4.1 H3C 인터넷 행동 관리 OAuth 설정

참고1: 172.20.0.2는 H3C 장비의 인밴드 주소이며, 사용자 환경에 맞게 IP만 변경하고 접미사는 변경하지 마세요. (스크립트에 고정됨)

참고2: 172.20.10.1은 Windows 서버 주소이며, 사용자 환경에 맞게 IP만 변경하고 접미사는 변경하지 마세요. (스크립트에 고정됨)

설정 항목입력 값
서버 이름Feishu 인증
설명H3C 인터넷 행동 관리 - Feishu OAuth 인증
콜백 주소http://172.20.0.2:8000/
appIDcli_a95XXXXXXXX
appSecreteaQ8UXXXXXXXX
리디렉션 URLhttp://172.20.10.1:8000/oauth/authorize
accessToken 획득 주소http://172.20.10.1:8000/oauth/token
accessToken 요청 유형POST
사용자 정보 요청 주소http://172.20.10.1:8000/oauth/userinfo
사용자 정보 요청 유형POST
사용자 정보 요청 매개변수client_id=cli_a95XXXXXXXX
인가 범위userinfo
획득 방식URL 매개변수
사용자 키워드username

4.2 Feishu 오픈 플랫폼 설정

  • 인가 주소: https://open.feishu.cn/open-apis/authen/v1/index
  • 토큰 인터페이스: https://open.feishu.cn/open-apis/authen/v1/access_token
  • 사용자 정보 인터페이스: https://open.feishu.cn/open-apis/authen/v1/user_info
  • 리디렉션 URL: http://172.20.10.1:8000/callback
  • 필수 권한: contact:user.base:readonly (사용자 기본 정보 읽기 전용)

4.3 비동기 미들웨어 핵심 설정

  • Feishu AppID / AppSecret: 운영 환경 실제 자격 증명 (Python 코드 내 해당 필드 수정)
  • 콜백 주소: http://172.20.10.1:8000/callback (사용자 서버 주소에 맞게 Python 코드 수정)
  • 토큰 만료 시간: 60초
  • 캐시 상한: 2000개 (메모리 오버플로우 방지)
  • 로그 경로: D:\login_log.txt

5. 운영 수준 비동기 미들웨어 전체 코드 (Python)


from fastapi import FastAPI, Request, Cookie, Form, HTTPException
from fastapi.responses import RedirectResponse
import httpx
import uuid
import datetime
from cachetools import TTLCache
import asyncio
import urllib3

# SSL 인증서 경고 비활성화
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

app = FastAPI(title="H3C Feishu 인증 서비스")

# ====================== 핵심 설정 (172.20.10.1을 사용자 서버 주소로 변경) ======================
FEISHU_APP_ID = "cli_a95XXXXXXX"
FEISHU_APP_SECRET = "eaQ8UXXXXXXX"
CALLBACK_URL = "http://172.20.10.1:8000/callback"
TOKEN_EXPIRE_SECONDS = 60
LOG_FILE = r"D:\login_log.txt"

# ====================== 메모리 캐시 (자동 만료, 오버플로우 방지) ======================
user_cache = TTLCache(maxsize=2000, ttl=TOKEN_EXPIRE_SECONDS)
cache_lock = asyncio.Lock()

# ====================== 로그 모듈 (성공/실패 분리) ======================
def write_success_log(name, user_id, mobile, ip):
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    log = f"[{now}] 이름={name} | 사용자ID={user_id} | 휴대폰={mobile} | IP주소={ip}\n"
    try:
        with open(LOG_FILE, "a", encoding="utf-8") as f:
            f.write(log)
    except Exception:
        pass

def write_error_log(msg):
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    log = f"[{now}] ERROR {msg}\n"
    try:
        with open(LOG_FILE, "a", encoding="utf-8") as f:
            f.write(log)
    except Exception:
        pass

# ====================== 비동기 HTTP 클라이언트 ======================
client = httpx.AsyncClient(timeout=5, verify=False)

# ====================== Feishu 인터페이스 재시도 메커니즘 (3회 재시도, 네트워크 변동 대비) ======================
async def feishu_request(method, url, **kwargs):
    for i in range(3):
        try:
            resp = await client.request(method, url, **kwargs)
            resp.raise_for_status()
            return resp.json()
        except Exception as e:
            if i == 2:
                write_error_log(f"Feishu 인터페이스 요청 실패: {str(e)}")
                raise
            await asyncio.sleep(0.5 * (i + 1))

# ====================== 핵심 비즈니스 인터페이스 ======================
# 1. H3C 인가 진입점: Feishu 인가 페이지로 리디렉션
@app.get("/oauth/authorize")
async def authorize(request: Request, redirect_uri: str = ""):
    url = (
        "https://open.feishu.cn/open-apis/authen/v1/index?"
        f"app_id={FEISHU_APP_ID}"
        f"&redirect_uri={CALLBACK_URL}"
        f"&response_type=code"
    )
    response = RedirectResponse(url)
    # H3C 콜백 주소 저장
    response.set_cookie("h3c_redirect", redirect_uri, max_age=120)
    return response

# 2. Feishu 인가 콜백: code 처리, 사용자 정보 획득
@app.get("/callback")
async def callback(code: str, request: Request, h3c_redirect: str = Cookie(None)):
    try:
        # 인가 코드로 Access Token 교환
        token_data = await feishu_request(
            "POST",
            "https://open.feishu.cn/open-apis/authen/v1/access_token",
            json={
                "app_id": FEISHU_APP_ID,
                "app_secret": FEISHU_APP_SECRET,
                "code": code,
                "grant_type": "authorization_code"
            }
        )
        access_token = token_data["data"]["access_token"]

        # Feishu 사용자 정보 획득
        user_data = await feishu_request(
            "GET",
            "https://open.feishu.cn/open-apis/authen/v1/user_info",
            headers={"Authorization": f"Bearer {access_token}"}
        )
        data = user_data["data"]

        # 사용자 필드 추출
        username = data.get("name", "")
        user_id = data.get("user_id", "")
        mobile = data.get("mobile", "")
        client_ip = request.client.host

        # 성공 로그 기록
        write_success_log(username, user_id, mobile, client_ip)

        # 사용자 정의 토큰 생성
        user_token = f"USER_{user_id}_{uuid.uuid4().hex[:8]}"

        # 캐시에 저장
        async with cache_lock:
            user_cache[user_token] = {
                "usercode": user_id,
                "username": username,
                "userorg": ""
            }

        # H3C 장비로 콜백
        if h3c_redirect:
            return RedirectResponse(f"{h3c_redirect}&code={user_token}&state=STATE")
        return {"code": user_token}

    except Exception as e:
        write_error_log(f"인증 실패: {str(e)}")
        raise HTTPException(status_code=500, detail="인증 실패")

# 3. H3C 토큰 획득 인터페이스
@app.post("/oauth/token")
async def token(code: str = Form(None)):
    return {
        "access_token": code,
        "token_type": "bearer",
        "expires_in": TOKEN_EXPIRE_SECONDS
    }

# 4. H3C 사용자 정보 획득 인터페이스 (평면 JSON, H3C 호환)
@app.post("/oauth/userinfo")
async def userinfo(access_token: str = Form(None)):
    try:
        async with cache_lock:
            return user_cache.get(access_token, {
                "usercode": "",
                "username": "",
                "userorg": ""
            })
    except Exception as e:
        write_error_log(f"userinfo 예외: {str(e)}")
        return {
            "usercode": "",
            "username": "",
            "userorg": ""
        }

# ====================== 서비스 시작 (운영 최적화) ======================
if __name__ == "__main__":
    import uvicorn

    # 컬러 로그 비활성화, Windows 깨짐 방지
    log_config = uvicorn.config.LOGGING_CONFIG
    log_config["formatters"]["default"]["use_colors"] = False
    log_config["formatters"]["access"]["use_colors"] = False

    print("==================================================")
    print("H3C Feishu 인증 서비스 시작 완료 (로그 커스텀 버전)")
    print("서비스 주소: http://0.0.0.0:8000")
    print(f"로그 파일: {LOG_FILE}")
    print("==================================================")

    uvicorn.run(
        app,
        host="0.0.0.0",
        port=8000,
        log_config=log_config,
        log_level="warning"
    )

6. 핵심 필드 매핑 및 상호 작용 분석

6.1 Feishu → 비동기 미들웨어 필드 변환

Feishu 중첩 필드미들웨어 평면 필드용도
data.nameusernameH3C에 표시할 사용자 이름
data.user_idusercode사용자 고유 식별자
공식 Access Token사용자 정의 임시 토큰세션 자격 증명

6.2 주요 인터페이스 분석

  • /oauth/authorize: H3C 인가 요청을 수신하여 Feishu QR 코드 페이지로 리디렉션
  • /callback: Feishu 인가 콜백, code 처리, 사용자 정보 획득, 데이터 형식화
  • /oauth/token: H3C가 요구하는 표준 OAuth2.0 Token 반환
  • /oauth/userinfo: H3C와 호환되는 평면 JSON 사용자 정보 반환

7. 운영 중常见 문제 및 해결 방안

7.1 오류: 웹 페이지 분석 실패, 지원되지 않는 페이지 유형일 수 있음

  • 근본 원인: H3C는 순수 JSON 응답만 인식하며, HTML/텍스트/오류 상태 코드와 호환되지 않음
  • 해결 방법: 미들웨어는 엄격하게 JSON을 반환하고, 불필요한 출력 없이 상태 코드 200 유지

7.2 오류: Feishu에서 '요청이 잘못되었습니다' 표시

  • 근본 원인: Feishu 리디렉션 URL과 미들웨어 CALLBACK_URL이 일치하지 않음
  • 해결 방법: Feishu 콘솔에서 http://172.20.10.1:8000/callback으로 설정

7.3 간헐적 인증 실패

  • 근본 원인: 서버 DNS 확인 불안정, 네트워크 변동
  • 해결 방법: 미들웨어 코드에 3회 재시도 메커니즘 추가

8. 운영 환경 최적화 포인트

  1. 비동기 논블로킹 아키텍처: FastAPI + httpx 비동기 처리, 단일 서버로 대량 동시 인증 처리 가능
  2. 메모리 안전성: TTLCache로 캐시 항목 수 제한 + 자동 만료, 메모리 사용량 낮고 안정적
  3. 로그 최적화: 성공/실패 로그 분리, 로컬 저장, 콘솔 출력 깨짐 없음
  4. 안정성: Feishu 인터페이스 3회 재시도, 네트워크 변동 대비
  5. 호환성: Windows/Linux 모든 플랫폼에서 실행 가능, 환경 의존성 없음

9. 결론

H3C 인터넷 행동 관리와 Feishu OAuth2.0은 직접 연결이 불가능하며, 핵심 병목은 Feishu의 중첩 JSONH3C의 평면 JSON 간의 형식 충돌 및 인터페이스 매개변수 규격 불일치입니다. 경량 비동기 미들웨어는 운영 환경에서 실행 가능한 솔루션으로, 유일한 중계 서비스로서 프로토콜 변환, 필드 매핑, 캐시 관리, 로그 추적 등 모든 기능을 담당하여 기업 직원이 Feishu QR 코드 한 번 스캔으로 인증 및 네트워크 접속을 완벽하게 구현합니다. 이 솔루션은 장시간, 높은 동시성의 운영 환경에서 검증되었으며, 안정적이고 신뢰할 수 있으며 배포 및 유지보수가 용이합니다.

부록: 의존성 설치 명령어


pip install fastapi uvicorn httpx cachetools

참고:

Windows 서버에서 8000 포트를 개방하려면 관리자 권한으로 PowerShell을 열고 다음 명령어를 실행합니다.


New-NetFirewallRule -DisplayName "PythonAuthServer-8000" -Direction Inbound -Protocol TCP -LocalPort 8000 -Action Allow

Linux 서버에서 8000 포트를 개방합니다.

Ubuntu:


sudo ufw allow 8000/tcp

CentOS:


sudo firewall-cmd --permanent --add-port=8000/tcp

태그: H3C SecPath ACG 1000 Feishu OAuth2.0

7월 17일 07:22에 게시됨