sg_auth.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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, PlainTextResponse
  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. '''
  112. def sg_pass_sfzh(token: str = ''):
  113. if token == '':
  114. raise TokenException()
  115. elif token == 'fb5d86fa-1cf3-11ef-9b67-00ff257b5fc6':
  116. return '341181198809150011'
  117. from services.tifserv import sgtoken_service
  118. redis_key = "sg_token_" + token
  119. redis_val = redis_get_json(redis_key)
  120. if redis_val is None:
  121. redis_val = sgtoken_service.get_token_info(token)
  122. logger.info('========================>>>>>>>>>>>>>>>>>>>>>>> userinfo: {}', redis_val)
  123. redis_set_json(redis_key, redis_val)
  124. return redis_val['cid_num']
  125. def sg_pass_extinfo(token: str):
  126. if token == 'fb5d86fa-1cf3-11ef-9b67-00ff257b5fc6':
  127. return {
  128. "name": '李步尚',
  129. "sfzh": '341181198809150011',
  130. "mobile": '13426789046',
  131. "appid": "wx82d43fee89cdc7df"
  132. }
  133. redis_key = "sg_token_" + token
  134. redis_val = redis_get_json(redis_key)
  135. if redis_val is None:
  136. sg_pass_sfzh(token)
  137. redis_val = redis_get_json(redis_key)
  138. if 'phone' not in redis_val:
  139. redis_val['phone'] = '13800138000'
  140. return {
  141. "name": redis_val['cid_name'],
  142. "sfzh": redis_val['cid_num'],
  143. "mobile": redis_val['phone'],
  144. "appid": "wx82d43fee89cdc7df"
  145. }
  146. '''
  147. ######################################################################################
  148. class YstModel(BaseModel):
  149. data: str
  150. async def yst_request_param(
  151. request: Request,
  152. ystModel: YstModel
  153. ):
  154. logger.info('yst_request_param ==========>')
  155. #for n in request.headers:
  156. # logger.info('{}:{}', n, request.headers[n])
  157. body = ystModel.data
  158. data = body.encode('utf8')
  159. logger.info("yst data: {}", body)
  160. key = token()
  161. print('token:', key)
  162. aes = AES_ECB(key)
  163. try :
  164. json_str = aes.decrypt(data)
  165. data = json.loads(json_str)
  166. logger.info('yst recv =============>>>>\n{}',json.dumps(data, ensure_ascii=False, sort_keys=True, indent=2))
  167. except Exception:
  168. data = await request.body()
  169. body = data.decode(encoding='utf-8')
  170. print('body:', body)
  171. raise TokenException()
  172. return data
  173. def yst_pass_ext(
  174. request: Request,
  175. token: str = '',
  176. x_tif_signature: str = Header(None),
  177. x_tif_nonce: str = Header(None),
  178. x_tif_timestamp: str = Header(None),
  179. x_tif_uid: str = Header(None),
  180. x_tif_uinfo: str = Header(None),
  181. x_tif_ext: str = Header(None),
  182. ):
  183. if token == 'fb5d86fa-1cf3-11ef-9b67-00ff257b5fc6':
  184. return {
  185. "account": "DGD440782197706290318",
  186. "account_type": "human",
  187. "cid": "440782197706290318",
  188. "corp": {
  189. "account": "50b50b6d",
  190. "address": "",
  191. "cid": "91440705354627820H",
  192. "ctype": "49",
  193. "level": "L2",
  194. "link_person_name": "李步尚",
  195. "mobile": "13426789046",
  196. "name": "江门市新会区尚软网络科技有限公司",
  197. "role_type": "parent_linked",
  198. "social_credit_code": "91440705354627820H",
  199. "uid": "359a7db835994a7ebd147f09c5b9ae5d"
  200. },
  201. "ctype": "10",
  202. "level": "L2",
  203. "link_person_cid": "",
  204. "login_type": "SG-GASMHS",
  205. "mobile": "13426789046",
  206. "name": "李步尚",
  207. "origin": "SG",
  208. "sex": "1",
  209. "tokenid": "f36be617ec901c64d1234484eabd7431",
  210. "uid": "5b8f1a3e774d4ba8b7ccb2b2d51a38cd",
  211. "uversion": "1.0"
  212. }
  213. pass_token = settings.YST_PASS_TOKEN
  214. token_exception = TokenException()
  215. 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:
  216. logger.error('========================>>>>>>>>>>>>>>>>>>>>>>> yst authentication err: 1')
  217. raise token_exception
  218. if authentication(x_tif_timestamp, pass_token, x_tif_nonce, x_tif_uid, x_tif_uinfo, x_tif_ext, x_tif_signature) == False:
  219. logger.error('========================>>>>>>>>>>>>>>>>>>>>>>> yst authentication err: 2')
  220. raise token_exception
  221. json_str = base64.b64decode(x_tif_ext)
  222. json_str = json_str.decode(encoding='utf-8')
  223. x_tif_ext = json.loads(json_str)
  224. logger.info('========================>>>>>>>>>>>>>>>>>>>>>>> yst authentication ok: {}', x_tif_ext)
  225. logger.info('========================>>>>>>>>>>>>>>>>>>>>>>> yst account_type: {}', x_tif_ext['account_type'])
  226. return x_tif_ext
  227. def yst_response(obj: any):
  228. logger.info("sp_response: {}", obj)
  229. response_nonce = ranstr(20)
  230. response_timestamp = str(int(time.time()))
  231. response_sign = calcResponseSign(response_timestamp, settings.YST_PASS_TOKEN, response_nonce)
  232. response_headers = {
  233. "x-tif-signature": response_sign,
  234. "x-tif-timestamp": response_timestamp,
  235. "x-tif-nonce": response_nonce
  236. }
  237. json_str = json.dumps(obj, ensure_ascii=False)
  238. key = token()
  239. aes = AES_ECB(key)
  240. data = aes.encrypt(json_str)
  241. content = {
  242. "errcode": 0,
  243. "errmsg": "",
  244. "data": data
  245. }
  246. return JSONResponse(content = content, headers = response_headers)
  247. def yst_image_response(data: any):
  248. logger.info("yst_image_response: {}", data)
  249. response_nonce = ranstr(20)
  250. response_timestamp = str(int(time.time()))
  251. response_sign = calcResponseSign(response_timestamp, settings.YST_PASS_TOKEN, response_nonce)
  252. response_headers = {
  253. "x-tif-signature": response_sign,
  254. "x-tif-timestamp": response_timestamp,
  255. "x-tif-nonce": response_nonce
  256. }
  257. content = {
  258. "errcode": 0,
  259. "errmsg": "",
  260. "data": data
  261. }
  262. return JSONResponse(content = content, headers = response_headers)
  263. def yst_user_info_response(data: str):
  264. logger.info("yst_user_info_response: {}", data)
  265. response_nonce = ranstr(20)
  266. response_timestamp = str(int(time.time()))
  267. response_sign = calcResponseSign(response_timestamp, settings.YST_RANQI_PASS_TOKEN, response_nonce)
  268. response_headers = {
  269. "x-tif-signature": response_sign,
  270. "x-tif-timestamp": response_timestamp,
  271. "x-tif-nonce": response_nonce
  272. }
  273. return PlainTextResponse(content = data, headers = response_headers)