Web接口服务
概述
exchange-web-api-backend提供了面向Web端和App端的JSON API,允许用户通过HTTP请求与交易所进行交互。
由于主体逻辑极其相似,因此该代码仓库中同时包含了面向app和面向web两套入口,但大部分逻辑是共享的。
启动命令:
- APP入口:
./main app_api - WEB入口:
./main web_api
主要中间件
middleware.AllowPathPrefixSkipper
用于在中间件链中跳过特定路径的处理,任何不在指定路径前缀下的请求都会被处理。
middleware.AllowPathPrefixNoSkipper
用于在中间件链中处理特定路径的请求。
middleware.RequestSizeLimiter
限制请求体的大小,防止过大的请求。
middleware.RateLimiterProvider
提供速率限制功能,防止恶意请求或流量过大导致服务不可用。
使用github.com/ulule/limiter/v3 库实现,支持多种存储后端。
middleware.TraceMiddleware
用于请求跟踪,记录请求的处理时间和相关信息。
middleware.MetricsProcessDuration
用于记录请求处理的时长,便于性能分析和优化。
middleware.RequestLoggerMiddleware
用于记录请求的详细信息,包括请求方法、路径、状态码等,便于日志分析。
middleware.ResponseLoggerMiddleware
用于记录响应的详细信息,包括响应状态码、响应时间等,便于日志分析。
jaegermw.Middleware
用于集成Jaeger进行分布式追踪,记录请求的调用链信息。
rpc.IPAccessMiddleware.IPAccessMiddleware
用于调用Core服务记录IP/用户访问日志。
rpc.IPLimitMiddleware.IPLimitMiddleware
用于IP限制,将会调用IP-Location服务验证IP地址是否合法。不合法的IP地址将被拒绝访问。
不合法的IP地址包括:
- 黑名单IP
- 不在允许的国家/地区范围内
- VPN/代理IP/Tor IP
rpc.SessionMiddleware.SessionMiddleware
用于会话管理,处理用户登录状态和会话信息。将会调用Auth服务验证用户的Session是否有效。
该中间件会在请求头中查询用户的Token,并将其转换为用户ID。
- Web:从Cookie中获取Token
- APP:从Authorization头中获取Token
cachenMW.Cache
用于缓存中间件,提供缓存功能以提高性能。
主要功能
验证码
使用Cloudflare的Turnstile服务进行验证码验证。前端将会在请求中包含Turnstile的Token,后端会验证该Token的有效性。
目前
以下接口需要进行验证码验证:
/user/auth/invite_key_validate (用户首次注册验证)
/user/auth/reset_password_pre (用户重置密码验证)
/user/auth/login_pre (用户登录验证)错误上报
任何GRPC远程调用发生的非预期错误都会通过MQ被上报到exchange-error-reporter。
如果需要避免错误上报,GRPC返回时需要使用FailedPrecondition状态码。
登录密码加密传输的前端逻辑
from base64 import b64decode, b64encode
from hashlib import sha256
import Crypto
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
password="atom1234"
public_key="MIIBCgKCAQEAxq5LDi1+GNDN/hKncHWqtVDSjag3e1ijgWPR/h+8PaNUdKZpH60sacPxCgNuaGAqH2neOCcmg2McEAaOB2FBsGTdSFacmQG4OBsq6Ivin3sbQnGuQcOsqfUNFmfW5o3PEimoKIN5ZEi22ui6srhyS5VU+BR+rsKkkEoYobtCDOSf/7cBlcSuskP4HjD/+yhutBPeR9j3RcOBT1/GSLA/sPpVCJb8FEfXIFR+qNbINieGcq26Ly82pc69v3Xy3q4TPvVUKAUN2STlG4IY0efWjbwmF97bEypRKLMw5Th8KgkO4h8vGZ12lQjF0LOt3LHzsbdmUOp02QSS6oGalmVYXQIDAQAB"
combined = password + email + "HKbitEX"
# combined = "atom1234btc-002@894568.xyzHKbitEX"
hashed_value = sha256(combined.encode()).hexdigest()
# hashed_value = "f4fb71f44a3e2b64df54bc8ab0adca03bf90a34e2c1d8a56047a6cad0b7a6c16"
key_bytes = b64decode(public_key)
rsa_key = RSA.import_key(key_bytes)
cipher = PKCS1_OAEP.new(rsa_key, hashAlgo=Crypto.Hash.SHA256)
encrypted = cipher.encrypt(pwd.encode())
encoded_message = b64encode(encrypted)
# encoded_message = "WDbRoy2WgSxoUUeMfbr7qGg2Jvyq+o75d0v4FYZEEkAn9mCnBvGtefq0iwebsxa/iUL8bU+OouQN8GKQw4eGGM4mRJRtU82ivPiv2cnOtQB+RQuerytx7ekEXFab...NzeDlzV8PvALwvfBcgtw6gW5qXXYJqG48IM2q2wkxo15Tw/uWitfkzOzZmT7BLQXnbKJFDKtnYEjWq+RRwUUYXB/p/9HhiNRFMws1dWzG9/FPnxlO2fB/S//hB+A=="
encoded_message_str = encoded_message.decode()
# encoded_message_str = "WDbRoy2WgSxoUUeMfbr7qGg2Jvyq+o75d0v4FYZEEkAn9mCnBvGtefq0iwebsxa/iUL8bU+OouQN8GKQw4eGGM4mRJRtU82ivPiv2cnOtQB+RQuerytx7ekEXFabr4h/zjE7I0KIwrVev/wewWRGQc4yKaaSRWhE4DMeMyw8WKTWTprnOxJBuFaj5fgEi1oRrkosmDa9Mq01DncB4w/8gVyLnANzeDlzV8PvALwvfBcgtw6gW5qXXYJqG48IM2q2wkxo15Tw/uWitfkzOzZmT7BLQXnbKJFDKtnYEjWq+RRwUUYXB/p/9HhiNRFMws1dWzG9/FPnxlO2fB/S//hB+A=="
# encoded_message_str = "BtwiEqt5EonvbmnMv3b0yNCsb9LuZWx6Zw12V1TBlOWcsqU2K8JLn2gRXRUfPylmtns0LZhwkuBdxQdhIAHIj/atqonBN5OD4xSBK3QcOPMuKAJ8Y9hqAsqy8Ol+IPKF398bc7esmXC7WZQK4u1faTXqETunUgpiFhjcPbmzFn5ZZltSs5mIRpZqsYme0l0gra0UjSRVIkEWwkbXzXlN/A1AH5yLN07udH97JbIAQkNkq2a3sAtoGdYgrX4gs0PyvJ8+N2Llb9WrTgV7WFgKKSQG/GAC4zl753KAm/MHhn0HzEn+ZDwECZGSI80Rf7dusjM3S934/QtUd1O+e9Yl+g=="
print(encoded_message_str)App登录方式
发送注册码邮件
POST /user/auth/register
{"two_fa_type": "mail_digits_6", "email": "btc-001@894568.xyz"}
{"code": "OK", "msg": ""}
仅验证注册码是否正确
POST /user/auth/invite_key_validate
{"two_fa_type": "mail_digits_6", "email": "btc-001@894568.xyz", "two_fa_code": "490698"}
{"code":"OK","msg":"","data":{"valid":true}}
用户设定密码
POST /user/auth/invite_complete
{"two_fa_type": "mail_digits_6", "email": "btc-002@894568.xyz", "two_fa_code": "149268", "name": "USRbtc-002@", "password": "atom1234"}
{"code":"OK","msg":"","data":{"user_id":"USER10109733194563781","email":"btc-002@894568.xyz","ga_verified":false,"avatar_url":"","kyc_identity_status":"","kyc_address_status":"","expire_at":1737003505436,"token":"Qz7x7OOSNWgISuzG_mOrsUpFmFsDO6u9cUJK-uwLWkdkC_LIzYVXNUgaejjilAI5"}}
看看Token是否能被正常解析 [DEBUG]
GET /user/auth/health
{"code":"OK","msg":"","data":"ok"}
获取用户信息
GET /user/auth/info
{"code": "OK", "msg": "", "data": {"user_id": "USER10109733194563781", "name": "USER10109733194563781", "enabled": True, "avatar_url": "", "attached_data": "", "email": "btc-002@894568.xyz", "ga_verified": False, "locking": False, "lock_until": 0, "kyc_identity_status": "", "kyc_address_status": "", "acl_objects": None}}
or
{"code": "ErrNeedLogin", "msg": "token expired", "XXXdebug_msg": "code: ErrNeedLogin, cat: 1, msg: token expired"}
作弊登录接口,一个email就拿到token,UAT及以上环境没有
POST /user/auth/easy_login [DEBUG ONLY]
{"code": "OK", "msg": "", "data": {"user_id": "USER10109733194563781", "email": "btc-002@894568.xyz", "ga_verified": False, "avatar_url": "", "kyc_identity_status": "", "kyc_address_status": "", "expire_at": 1737003780789, "token": "ekoMF2NvaAucchpotTi-yxV-BbbmaiknBZo6WbdDfy_5m4wV3Yl_uG1EfMqO-yHN"}}
预登录,请求一个RSA OAEP 公钥
POST /user/auth/login_wrap
{"email": "btc-002@894568.xyz"}
{"code":"OK","msg":"","data":{"k":"MIIBCgKCAQEAtAU9MG1b0zXs5bTrd0D80TTNQhaLFlExVsQyaDP5xiwctiJY72zUmJOEPYHsshqGu3OAuw0Xyb3NNovba78MG2CPJUOQNCHMVMQRC6nF1O+Avdvp8dgWbLG9/0ah8V/XMMZmoyQg2r3XQ6VHiNAl0ywVhZscY9ejUa35lPFWQPz7fqyiuAuBDvZSopCJzVpopkiOdbKaB9Ads/5GP2aKnsAyOqbaEb2prWazx0gxnwNfU48y7IMUOSz8isS7gvr1ztZ1pK9YROF3kXXjZPB82WN29sNm8PiFjzgmxHuPgEKvzRVxd1VylZMXi6mrn57JqWAruxomeVqn9sJfVlDwsQIDAQAB","nonce":"132412255"}}
提交用户名密码,换一个verification,进行后续验证操作(password)
POST /user/auth/login_pre
{"email":"btc-001@894568.xyz","password":"WpIOuz1sWQNcCga7UlJZXA/EQz3WGsXkDTTuxeeEjVywjt8WeY9VlanlEMaO10jJK6sDl0otisb5WQ1rpkFF2tnLlr3GXhVA7uF7Cqw3gDP0kpQ5qcjsRh0tYpAgT8fPeb2aO9iBWsyoXWZmkab3Gg/D4XeLNh+TJWjjw2wRH2lQkWTqPcd3PPIys7Po/Cmy/3QigAyuo3E4SRyWgD6ytchPxPK7Iu4Cvs+H607gounEQsZDDV7RmTqmNuHE1rMItveT8Y+hN1HT4s7I95iQNqgYNxapYgTg7+sMt6cVz5knlxycIdA/D64ovhTPnz91GqTU+hS3HsemW6unX6LdQQ==","nonce":"6624867","g-recaptcha-response":"192939"}
NORMAL RESPONSE
{"code":"OK","msg":"","data":{"verification_status":{"verification_id":"VER10110080666836805","done":false,"need_two_fa":true,"two_fa_done":false,"need_ga":false,"ga_done":false,"need_password":true,"password_done":true}}}
BAD RESPONSE
{"code": "ErrInvalidCredential","msg":"","XXXdebug_msg":"user:invalid credential"}
{"code": "ErrInternal", "msg": "internal error", "XXXdebug_msg": "crypto/rsa: decryption error"}
{"code": "ErrInvalidEncryptionId", "msg": "invalid encryption id", "XXXdebug_msg": "code: ErrInvalidEncryptionId, cat: 1, msg: invalid encryption id"}
对一个verification申请邮件code
POST /user/verification/send_two_fa_anonymous
{"email":"btc-002@894568.xyz","verification_id":"VER10110080666836805"}
{"code":"OK","msg":"","data":""}
使用一个code填满verification,如果verification.done=true则所有验证都OK了
POST /user/verification/submit_anonymous
{"email":"btc-002@894568.xyz","verification_id":"VER10110080666836805","two_fa_code":"192939"}
{"code":"OK","msg":"","data":{"verification_id":"VER10110080666836805","done":true,"need_two_fa":true,"two_fa_done":true,"need_ga":false,"ga_done":false,"need_password":true,"password_done":true}}
提供一个未使用的完成验证的verification,进行登录
POST /user/auth/login
{"email":"btc-002@894568.xyz","verification_id":"VER10110080666836805"}
{"code":"OK","msg":"","data":{"user_id":"USER8923173285329413","email":"btc-002@894568.xyz","ga_verified":false,"avatar_url":"","kyc_identity_status":"","kyc_address_status":"", "expire_at":1737003505436,"token":"Qz7x7OOSNWgISuzG_mOrsUpFmFsDO6u9cUJK-uwLWkdkC_LIzYVXNUgaejjilAI5"}}
{"code":"ErrIncorrectVerification","msg":"","XXXdebug_msg":"core:incorrect verification"}
登出
POST /user/auth/logout
{"code":"OK","msg":"","data":""}