312 lines
10 KiB
Python
312 lines
10 KiB
Python
|
|
from flask import request, jsonify, current_app
|
|||
|
|
from datetime import datetime, timedelta
|
|||
|
|
from app import db
|
|||
|
|
from app.models import Product, License, Device, Version
|
|||
|
|
from app.utils.crypto import generate_hash, verify_hash, generate_signature
|
|||
|
|
from . import api_bp
|
|||
|
|
|
|||
|
|
@api_bp.route('/auth/verify', methods=['POST'])
|
|||
|
|
def verify_license():
|
|||
|
|
"""验证卡密接口"""
|
|||
|
|
try:
|
|||
|
|
data = request.get_json()
|
|||
|
|
if not data:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '请求数据为空'
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# 获取请求参数
|
|||
|
|
software_id = data.get('software_id')
|
|||
|
|
license_key = data.get('license_key')
|
|||
|
|
machine_code = data.get('machine_code')
|
|||
|
|
timestamp = data.get('timestamp')
|
|||
|
|
signature = data.get('signature')
|
|||
|
|
|
|||
|
|
# 验证必填参数
|
|||
|
|
if not all([software_id, license_key, machine_code, timestamp, signature]):
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '缺少必要参数'
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# 验证时间戳(防止重放攻击)
|
|||
|
|
try:
|
|||
|
|
request_time = datetime.fromtimestamp(int(timestamp))
|
|||
|
|
# 增加时间验证的宽容度到5分钟(300秒)
|
|||
|
|
time_diff = abs((datetime.utcnow() - request_time).total_seconds())
|
|||
|
|
if time_diff > 300: # 5分钟有效期
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '请求已过期'
|
|||
|
|
}), 400
|
|||
|
|
except (ValueError, TypeError):
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '时间戳格式错误'
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# 验证签名
|
|||
|
|
secret_key = current_app.config.get('AUTH_SECRET_KEY', 'default-secret-key')
|
|||
|
|
signature_data = f"{software_id}{license_key}{machine_code}{timestamp}"
|
|||
|
|
expected_signature = generate_signature(signature_data, secret_key)
|
|||
|
|
|
|||
|
|
# 添加调试信息
|
|||
|
|
current_app.logger.info(f"签名数据: {signature_data}")
|
|||
|
|
current_app.logger.info(f"客户端签名: {signature}")
|
|||
|
|
current_app.logger.info(f"服务端签名: {expected_signature}")
|
|||
|
|
current_app.logger.info(f"签名是否匹配: {signature == expected_signature}")
|
|||
|
|
current_app.logger.info(f"服务端密钥: {secret_key}")
|
|||
|
|
|
|||
|
|
if signature != expected_signature:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '签名验证失败'
|
|||
|
|
}), 401
|
|||
|
|
|
|||
|
|
# 查找产品
|
|||
|
|
product = Product.query.filter_by(product_id=software_id).first()
|
|||
|
|
if not product:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '产品不存在'
|
|||
|
|
}), 404
|
|||
|
|
|
|||
|
|
if not product.is_enabled():
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '产品已禁用'
|
|||
|
|
}), 403
|
|||
|
|
|
|||
|
|
# 查找卡密
|
|||
|
|
license_obj = License.query.filter_by(
|
|||
|
|
license_key=license_key,
|
|||
|
|
product_id=software_id
|
|||
|
|
).first()
|
|||
|
|
|
|||
|
|
if not license_obj:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '卡密不存在'
|
|||
|
|
}), 404
|
|||
|
|
|
|||
|
|
# 验证卡密
|
|||
|
|
software_version = request.json.get('software_version', '1.0.0') if request.json else '1.0.0'
|
|||
|
|
success, message = license_obj.verify(machine_code, software_version)
|
|||
|
|
if not success:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': message
|
|||
|
|
}), 403
|
|||
|
|
|
|||
|
|
# 处理首次激活
|
|||
|
|
if license_obj.status == 0: # 未激活
|
|||
|
|
software_version = request.json.get('software_version', '1.0.0') if request.json else '1.0.0'
|
|||
|
|
success, message = license_obj.activate(
|
|||
|
|
machine_code,
|
|||
|
|
software_version
|
|||
|
|
)
|
|||
|
|
if not success:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': message
|
|||
|
|
}), 403
|
|||
|
|
|
|||
|
|
# 更新设备验证时间
|
|||
|
|
device = Device.query.filter_by(machine_code=machine_code).first()
|
|||
|
|
if device:
|
|||
|
|
device.update_verify_time()
|
|||
|
|
|
|||
|
|
# 获取最新版本信息
|
|||
|
|
latest_version = Version.query.filter_by(
|
|||
|
|
product_id=software_id,
|
|||
|
|
publish_status=1
|
|||
|
|
).order_by(Version.create_time.desc()).first()
|
|||
|
|
|
|||
|
|
response_data = {
|
|||
|
|
'license_key': license_obj.license_key,
|
|||
|
|
'type': license_obj.type,
|
|||
|
|
'type_name': '试用' if license_obj.is_trial() else '正式',
|
|||
|
|
'expire_time': license_obj.expire_time.isoformat() if license_obj.expire_time else None,
|
|||
|
|
'remaining_days': license_obj.get_remaining_days(),
|
|||
|
|
'product_name': product.product_name,
|
|||
|
|
'activate_time': license_obj.activate_time.isoformat() if license_obj.activate_time else None
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 添加版本信息
|
|||
|
|
if latest_version:
|
|||
|
|
current_version = request.json.get('software_version', '1.0.0') if request.json else '1.0.0'
|
|||
|
|
response_data.update({
|
|||
|
|
'new_version': latest_version.version_num,
|
|||
|
|
'download_url': latest_version.download_url,
|
|||
|
|
'force_update': latest_version.is_force_update(),
|
|||
|
|
'update_log': latest_version.update_log,
|
|||
|
|
'need_update': latest_version.version_num != current_version
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return jsonify({
|
|||
|
|
'success': True,
|
|||
|
|
'message': '验证成功',
|
|||
|
|
'data': response_data
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
current_app.logger.error(f"卡密验证失败: {str(e)}")
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '服务器内部错误'
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
@api_bp.route('/auth/activate', methods=['POST'])
|
|||
|
|
def activate_license():
|
|||
|
|
"""激活卡密接口"""
|
|||
|
|
try:
|
|||
|
|
data = request.get_json()
|
|||
|
|
if not data:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '请求数据为空'
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
software_id = data.get('software_id')
|
|||
|
|
license_key = data.get('license_key')
|
|||
|
|
machine_code = data.get('machine_code')
|
|||
|
|
software_version = data.get('software_version', '1.0.0')
|
|||
|
|
|
|||
|
|
# 验证必填参数
|
|||
|
|
if not all([software_id, license_key, machine_code]):
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '缺少必要参数'
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# 查找产品
|
|||
|
|
product = Product.query.filter_by(product_id=software_id).first()
|
|||
|
|
if not product:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '产品不存在'
|
|||
|
|
}), 404
|
|||
|
|
|
|||
|
|
# 查找卡密
|
|||
|
|
license_obj = License.query.filter_by(
|
|||
|
|
license_key=license_key,
|
|||
|
|
product_id=software_id
|
|||
|
|
).first()
|
|||
|
|
|
|||
|
|
if not license_obj:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '卡密不存在'
|
|||
|
|
}), 404
|
|||
|
|
|
|||
|
|
# 激活卡密
|
|||
|
|
success, message = license_obj.activate(machine_code, software_version)
|
|||
|
|
if not success:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': message
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
return jsonify({
|
|||
|
|
'success': True,
|
|||
|
|
'message': '激活成功',
|
|||
|
|
'data': license_obj.to_dict()
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
current_app.logger.error(f"卡密激活失败: {str(e)}")
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '服务器内部错误'
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
@api_bp.route('/auth/info', methods=['GET'])
|
|||
|
|
def get_auth_info():
|
|||
|
|
"""获取授权信息接口"""
|
|||
|
|
try:
|
|||
|
|
software_id = request.args.get('software_id')
|
|||
|
|
machine_code = request.args.get('machine_code')
|
|||
|
|
|
|||
|
|
if not software_id or not machine_code:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '缺少必要参数'
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# 查找设备
|
|||
|
|
device = Device.query.filter_by(
|
|||
|
|
machine_code=machine_code,
|
|||
|
|
status=1
|
|||
|
|
).first()
|
|||
|
|
|
|||
|
|
if not device:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '设备未激活'
|
|||
|
|
}), 404
|
|||
|
|
|
|||
|
|
# 查找关联的卡密
|
|||
|
|
license_obj = device.license
|
|||
|
|
if not license_obj or license_obj.product_id != software_id:
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '授权信息不匹配'
|
|||
|
|
}), 403
|
|||
|
|
|
|||
|
|
# 检查授权状态
|
|||
|
|
if license_obj.is_expired():
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '授权已过期'
|
|||
|
|
}), 403
|
|||
|
|
|
|||
|
|
# 返回授权信息
|
|||
|
|
return jsonify({
|
|||
|
|
'success': True,
|
|||
|
|
'data': {
|
|||
|
|
'license_key': license_obj.license_key,
|
|||
|
|
'type': license_obj.type,
|
|||
|
|
'type_name': '试用' if license_obj.is_trial() else '正式',
|
|||
|
|
'expire_time': license_obj.expire_time.isoformat() if license_obj.expire_time else None,
|
|||
|
|
'remaining_days': license_obj.get_remaining_days(),
|
|||
|
|
'activate_time': license_obj.activate_time.isoformat() if license_obj.activate_time else None,
|
|||
|
|
'last_verify_time': license_obj.last_verify_time.isoformat() if license_obj.last_verify_time else None
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
current_app.logger.error(f"获取授权信息失败: {str(e)}")
|
|||
|
|
return jsonify({
|
|||
|
|
'success': False,
|
|||
|
|
'message': '服务器内部错误'
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
@api_bp.route('/auth/heartbeat', methods=['POST'])
|
|||
|
|
def heartbeat():
|
|||
|
|
"""心跳接口(用于在线验证)"""
|
|||
|
|
try:
|
|||
|
|
data = request.get_json()
|
|||
|
|
if not data:
|
|||
|
|
return jsonify({'success': False}), 400
|
|||
|
|
|
|||
|
|
software_id = data.get('software_id')
|
|||
|
|
machine_code = data.get('machine_code')
|
|||
|
|
|
|||
|
|
if not software_id or not machine_code:
|
|||
|
|
return jsonify({'success': False}), 400
|
|||
|
|
|
|||
|
|
# 更新设备最后验证时间
|
|||
|
|
device = Device.query.filter_by(
|
|||
|
|
machine_code=machine_code,
|
|||
|
|
status=1
|
|||
|
|
).first()
|
|||
|
|
|
|||
|
|
if device:
|
|||
|
|
device.update_verify_time()
|
|||
|
|
|
|||
|
|
return jsonify({'success': True})
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
current_app.logger.error(f"心跳处理失败: {str(e)}")
|
|||
|
|
return jsonify({'success': False}), 500
|