sg_auth.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. # -*- coding: utf-8 -*-
  2. from fastapi import Request, Header
  3. from pydantic import BaseModel
  4. import random
  5. import string
  6. import hashlib
  7. import time
  8. import base64
  9. import json
  10. from starlette.responses import JSONResponse
  11. from config import settings
  12. from exceptions import TokenException
  13. from extensions import logger
  14. from .aes_util import AES_ECB
  15. from datetime import datetime
  16. from .redis_util import *
  17. ################################################################
  18. ##
  19. ##
  20. ## 数广网关
  21. ##
  22. ##
  23. ################################################################
  24. # 随机字符串
  25. def ranstr(num):
  26. salt = ''.join(random.sample(string.ascii_letters + string.digits, num))
  27. return salt
  28. # 网关验证
  29. def authentication(timestamp, token, nonce, uid, uinfo, ext, signature):
  30. sign_data_sha256 = calcRequestSign(timestamp, token, nonce, uid, uinfo, ext)
  31. return sign_data_sha256 == signature.upper()
  32. # 验证反馈值
  33. def calcResponseSign(timestamp, token, nonce):
  34. sign_data = "{}{}{}{}".format(timestamp, token, nonce, timestamp)
  35. return hashlib.sha256(sign_data.encode("utf8")).hexdigest().upper()
  36. # 生成sign
  37. def calcRequestSign(timestamp, token, nonce, uid, uinfo, ext):
  38. sign_data = "{}{}{},{},".format(timestamp, token, nonce, uid)
  39. if len(uinfo) == 0:
  40. sign_data = sign_data + ","
  41. else:
  42. sign_data = sign_data + uinfo + ","
  43. if len(ext) == 0:
  44. sign_data = sign_data
  45. else:
  46. sign_data = sign_data + ext
  47. sign_data = sign_data + timestamp
  48. return hashlib.sha256(sign_data.encode("utf8")).hexdigest().upper()
  49. # 生成自定义token
  50. def token() -> str:
  51. d1 = datetime.today()
  52. weekday = d1.weekday()+1
  53. if weekday == 7:
  54. weekday = 0
  55. tokenStr = 'yss_bdc' + str(d1.month) + str(d1.day) + str(weekday) + str(d1.year)
  56. m = hashlib.md5()
  57. m.update(tokenStr.encode('ascii'))
  58. token_md5 = m.hexdigest()
  59. return token_md5[0:16]
  60. # 按网关要求生成数据
  61. def sg_response(
  62. obj: any
  63. ):
  64. logger.info("sp_response: {}", obj)
  65. response_nonce = ranstr(20)
  66. response_timestamp = str(int(time.time()))
  67. response_sign = calcResponseSign(response_timestamp, settings.GSPT_PASS_TOKEN, response_nonce)
  68. response_headers = {
  69. "x-tif-signature": response_sign,
  70. "x-tif-timestamp": response_timestamp,
  71. "x-tif-nonce": response_nonce
  72. }
  73. json_str = json.dumps(obj, ensure_ascii=False)
  74. key = token()
  75. aes = AES_ECB(key)
  76. data = aes.encrypt(json_str)
  77. content = {
  78. "errcode": 0,
  79. "errmsg": "",
  80. "data": data
  81. }
  82. return JSONResponse(content = content, headers = response_headers)
  83. def pt_sg_response(obj: any
  84. ):
  85. json_str = json.dumps(obj, ensure_ascii=False)
  86. key = token()
  87. aes = AES_ECB(key)
  88. data = aes.encrypt(json_str)
  89. content = {
  90. "errcode": 0,
  91. "errmsg": "",
  92. "data": data
  93. }
  94. return JSONResponse(content = content)
  95. # 读取网关参数
  96. async def sg_request_param(request: Request):
  97. data = await request.body()
  98. body = data.decode(encoding='utf-8')
  99. key = token()
  100. aes = AES_ECB(key)
  101. try :
  102. # print('aes key:', key)
  103. # print('aes data:', body)
  104. json_str = aes.decrypt(data)
  105. data = json.loads(json_str)
  106. logger.info('sg recv =============>>>>\n{}',json.dumps(data, ensure_ascii=False, sort_keys=True, indent=2))
  107. except Exception:
  108. print('err body:', body)
  109. raise TokenException()
  110. return data
  111. def sg_pass_sfzh(token: str = ''):
  112. if token == '':
  113. raise TokenException()
  114. elif token == 'fb5d86fa-1cf3-11ef-9b67-00ff257b5fc6':
  115. return '341181198809150011'
  116. from services.tifserv import sgtoken_service
  117. redis_key = "sg_token_" + token
  118. redis_val = redis_get_json(redis_key)
  119. if redis_val is None:
  120. redis_val = sgtoken_service.get_token_info(token)
  121. logger.info('========================>>>>>>>>>>>>>>>>>>>>>>> userinfo: {}', redis_val)
  122. redis_set_json(redis_key, redis_val)
  123. return redis_val['cid_num']
  124. def sg_pass_extinfo(token: str):
  125. if token == 'fb5d86fa-1cf3-11ef-9b67-00ff257b5fc6':
  126. return {
  127. "name": '李步尚',
  128. "sfzh": '341181198809150011',
  129. "mobile": '13426789046',
  130. "appid": "wx82d43fee89cdc7df"
  131. }
  132. redis_key = "sg_token_" + token
  133. redis_val = redis_get_json(redis_key)
  134. if redis_val is None:
  135. sg_pass_sfzh(token)
  136. redis_val = redis_get_json(redis_key)
  137. if 'phone' not in redis_val:
  138. redis_val['phone'] = '13800138000'
  139. return {
  140. "name": redis_val['cid_name'],
  141. "sfzh": redis_val['cid_num'],
  142. "mobile": redis_val['phone'],
  143. "appid": "wx82d43fee89cdc7df"
  144. }
  145. ######################################################################################
  146. class YstModel(BaseModel):
  147. data: str
  148. async def yst_request_param(
  149. request: Request,
  150. ystModel: YstModel
  151. ):
  152. logger.info('yst_request_param ==========>')
  153. #for n in request.headers:
  154. # logger.info('{}:{}', n, request.headers[n])
  155. body = ystModel.data
  156. data = body.encode('utf8')
  157. logger.info("yst data: {}", body)
  158. key = token()
  159. print('token:', key)
  160. aes = AES_ECB(key)
  161. try :
  162. json_str = aes.decrypt(data)
  163. data = json.loads(json_str)
  164. logger.info('yst recv =============>>>>\n{}',json.dumps(data, ensure_ascii=False, sort_keys=True, indent=2))
  165. except Exception:
  166. data = await request.body()
  167. body = data.decode(encoding='utf-8')
  168. print('body:', body)
  169. raise TokenException()
  170. return data
  171. def yst_pass_ext(
  172. request: Request,
  173. x_tif_signature: str = Header(None),
  174. x_tif_nonce: str = Header(None),
  175. x_tif_timestamp: str = Header(None),
  176. x_tif_uid: str = Header(None),
  177. x_tif_uinfo: str = Header(None),
  178. x_tif_ext: str = Header(None),
  179. ):
  180. return {
  181. "account": "DGD440782197706290318",
  182. "account_type": "human",
  183. "cid": "440782197706290318",
  184. "corp": {
  185. "account": "50b50b6d",
  186. "address": "",
  187. "cid": "91440705354627820H",
  188. "ctype": "49",
  189. "level": "L2",
  190. "link_person_name": "李步尚",
  191. "mobile": "13426789046",
  192. "name": "江门市新会区尚软网络科技有限公司",
  193. "role_type": "parent_linked",
  194. "social_credit_code": "91440705354627820H",
  195. "uid": "359a7db835994a7ebd147f09c5b9ae5d"
  196. },
  197. "ctype": "10",
  198. "level": "L2",
  199. "link_person_cid": "",
  200. "login_type": "SG-GASMHS",
  201. "mobile": "13426789046",
  202. "name": "李步尚",
  203. "origin": "SG",
  204. "sex": "1",
  205. "tokenid": "f36be617ec901c64d1234484eabd7431",
  206. "uid": "5b8f1a3e774d4ba8b7ccb2b2d51a38cd",
  207. "uversion": "1.0"
  208. }
  209. pass_token = settings.YST_PASS_TOKEN
  210. token_exception = TokenException()
  211. if x_tif_signature is None or x_tif_nonce is None or x_tif_timestamp is None or x_tif_uid is None or x_tif_uinfo is None or x_tif_ext is None:
  212. logger.error('========================>>>>>>>>>>>>>>>>>>>>>>> yst authentication err: 1')
  213. raise token_exception
  214. if authentication(x_tif_timestamp, pass_token, x_tif_nonce, x_tif_uid, x_tif_uinfo, x_tif_ext, x_tif_signature) == False:
  215. logger.error('========================>>>>>>>>>>>>>>>>>>>>>>> yst authentication err: 2')
  216. raise token_exception
  217. json_str = base64.b64decode(x_tif_ext)
  218. json_str = json_str.decode(encoding='utf-8')
  219. x_tif_ext = json.loads(json_str)
  220. logger.info('========================>>>>>>>>>>>>>>>>>>>>>>> yst authentication ok: {}', x_tif_ext)
  221. logger.info('========================>>>>>>>>>>>>>>>>>>>>>>> yst account_type: {}', x_tif_ext['account_type'])
  222. return x_tif_ext
  223. def yst_response(obj: any):
  224. logger.info("sp_response: {}", obj)
  225. response_nonce = ranstr(20)
  226. response_timestamp = str(int(time.time()))
  227. response_sign = calcResponseSign(response_timestamp, settings.YST_PASS_TOKEN, response_nonce)
  228. response_headers = {
  229. "x-tif-signature": response_sign,
  230. "x-tif-timestamp": response_timestamp,
  231. "x-tif-nonce": response_nonce
  232. }
  233. json_str = json.dumps(obj, ensure_ascii=False)
  234. key = token()
  235. aes = AES_ECB(key)
  236. data = aes.encrypt(json_str)
  237. content = {
  238. "errcode": 0,
  239. "errmsg": "",
  240. "data": data
  241. }
  242. return JSONResponse(content = content, headers = response_headers)
  243. def yst_image_response(data: any):
  244. logger.info("yst_image_response: {}", data)
  245. response_nonce = ranstr(20)
  246. response_timestamp = str(int(time.time()))
  247. response_sign = calcResponseSign(response_timestamp, settings.YST_PASS_TOKEN, response_nonce)
  248. response_headers = {
  249. "x-tif-signature": response_sign,
  250. "x-tif-timestamp": response_timestamp,
  251. "x-tif-nonce": response_nonce
  252. }
  253. content = {
  254. "errcode": 0,
  255. "errmsg": "",
  256. "data": data
  257. }
  258. return JSONResponse(content = content, headers = response_headers)