Files
cclabel-auth-server/app.py
시골약사 06d0098a43 초기 커밋: 인증 서버 분리
0bin-label-app 프로젝트의 auth 폴더에서 별도 리포지토리로 분리.

Flask 기반 로그인 인증 서버:
- POST /api/login: 클라이언트 로그인 API
- GET /api/health: 서버 상태 확인
- /admin: 관리자 웹 페이지
- SQLite 기반 사용자 및 로그인 기록 저장

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 08:57:55 +09:00

198 lines
5.9 KiB
Python

# app.py
# 0bin Label App 인증 서버 (Flask)
from flask import Flask, request, jsonify, render_template, redirect, url_for, session
from models import db, User, LoginLog
from datetime import datetime
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-change-this-in-production'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///auth_db.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# DB 초기화
db.init_app(app)
# ============================================================
# API 엔드포인트 (클라이언트용)
# ============================================================
@app.route('/api/login', methods=['POST'])
def api_login():
"""클라이언트 로그인 API"""
try:
data = request.get_json()
username = data.get('username', '').strip()
password = data.get('password', '').strip()
if not username or not password:
return jsonify({
'success': False,
'message': '아이디와 비밀번호를 입력하세요'
}), 400
# 사용자 조회
user = User.query.filter_by(username=username).first()
# 로그인 시도 기록
ip_address = request.remote_addr
user_agent = request.headers.get('User-Agent', '')
if user and user.is_active and user.check_password(password):
# 로그인 성공
log = LoginLog(
user_id=user.id,
ip_address=ip_address,
user_agent=user_agent,
success=True
)
db.session.add(log)
db.session.commit()
return jsonify({
'success': True,
'message': '로그인 성공',
'username': user.username
}), 200
else:
# 로그인 실패
if user:
log = LoginLog(
user_id=user.id,
ip_address=ip_address,
user_agent=user_agent,
success=False
)
db.session.add(log)
db.session.commit()
return jsonify({
'success': False,
'message': '아이디 또는 비밀번호가 올바르지 않습니다'
}), 401
except Exception as e:
return jsonify({
'success': False,
'message': f'서버 오류: {str(e)}'
}), 500
@app.route('/api/health', methods=['GET'])
def api_health():
"""서버 상태 확인"""
return jsonify({
'status': 'ok',
'timestamp': datetime.utcnow().isoformat()
}), 200
# ============================================================
# Admin 페이지 (웹 UI)
# ============================================================
@app.route('/')
def index():
"""메인 페이지 - Admin 로그인으로 리다이렉트"""
return redirect(url_for('admin_login'))
@app.route('/admin', methods=['GET'])
def admin_login():
"""Admin 로그인 페이지"""
if 'admin_logged_in' in session:
return redirect(url_for('admin_dashboard'))
return render_template('login.html')
@app.route('/admin/login', methods=['POST'])
def admin_login_post():
"""Admin 로그인 처리"""
username = request.form.get('username', '').strip()
password = request.form.get('password', '').strip()
# 간단한 admin 계정 (하드코딩)
# 실제 운영 시에는 별도 Admin 테이블 사용 권장
if username == 'admin' and password == 'admin1234':
session['admin_logged_in'] = True
session['admin_username'] = username
return redirect(url_for('admin_dashboard'))
else:
return render_template('login.html', error='잘못된 관리자 계정입니다')
@app.route('/admin/logout')
def admin_logout():
"""Admin 로그아웃"""
session.pop('admin_logged_in', None)
session.pop('admin_username', None)
return redirect(url_for('admin_login'))
@app.route('/admin/dashboard')
def admin_dashboard():
"""Admin 대시보드"""
if 'admin_logged_in' not in session:
return redirect(url_for('admin_login'))
# 사용자 목록
users = User.query.all()
# 최근 로그인 기록 (최대 50개)
recent_logs = LoginLog.query.order_by(
LoginLog.login_time.desc()
).limit(50).all()
# 통계
total_users = User.query.count()
total_logins = LoginLog.query.filter_by(success=True).count()
failed_logins = LoginLog.query.filter_by(success=False).count()
return render_template(
'dashboard.html',
users=users,
recent_logs=recent_logs,
total_users=total_users,
total_logins=total_logins,
failed_logins=failed_logins
)
# ============================================================
# DB 초기화
# ============================================================
def init_db():
"""데이터베이스 초기화 및 test 계정 생성"""
with app.app_context():
# 테이블 생성
db.create_all()
# test 계정이 없으면 생성
test_user = User.query.filter_by(username='test').first()
if not test_user:
test_user = User(username='test')
test_user.set_password('test')
db.session.add(test_user)
db.session.commit()
print('[DB] test/test 계정 생성 완료')
else:
print('[DB] test 계정 이미 존재')
if __name__ == '__main__':
# DB 초기화
if not os.path.exists('auth_db.sqlite'):
print('[DB] 데이터베이스 생성 중...')
init_db()
else:
print('[DB] 기존 데이터베이스 사용')
# Flask 서버 실행 (8898 포트)
print('[서버] 인증 서버 시작: http://0.0.0.0:8898')
print('[서버] Admin 페이지: http://localhost:8898/admin')
print('[서버] API 엔드포인트: http://localhost:8898/api/login')
app.run(host='0.0.0.0', port=8898, debug=True)