Object.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. # -*- encoding: utf-8 -*-
  2. """
  3. @File : AmazonS3Util.py
  4. @Time : 2022/8/11 14:00
  5. @Author : stephen
  6. @Email : zhangdongming@asj6.wecom.work
  7. @Software: PyCharm
  8. """
  9. import time
  10. import traceback
  11. import redis
  12. import boto3
  13. import botocore
  14. from boto3.session import Session
  15. from botocore import client
  16. from botocore.exceptions import ClientError
  17. import jwt
  18. import datetime
  19. SERVER_HOST = '127.0.0.1' # 本地节点
  20. OAUTH_ACCESS_TOKEN_SECRET = 'a+jbgnw%@1%zy^=@dn62%'
  21. OAUTH_REFRESH_TOKEN_SECRET = 'r+jbgnw%@1%zy^=@dn62%'
  22. # access_token超时
  23. OAUTH_ACCESS_TOKEN_TIME = datetime.timedelta(days=30)
  24. # refresh_token超时
  25. OAUTH_REFRESH_TOKEN_TIME = datetime.timedelta(days=30)
  26. class AmazonS3Util:
  27. def __init__(self):
  28. self.access_id = 'AKIA2E67UIMD45Y3HL53'
  29. self.access_secret = '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'
  30. self.region_name = 'us-east-1'
  31. session = Session(
  32. aws_access_key_id=self.access_id,
  33. aws_secret_access_key=self.access_secret,
  34. region_name=self.region_name
  35. )
  36. self.client_conn = boto3.client(
  37. 's3',
  38. aws_access_key_id=self.access_id,
  39. aws_secret_access_key=self.access_secret,
  40. config=botocore.client.Config(signature_version='s3v4'),
  41. region_name=self.region_name
  42. )
  43. self.session_conn = session.resource('s3')
  44. def upload_file_obj(self, bucket, file_key, file_obj, extra_args=None):
  45. """
  46. 对象上传至S3存储桶
  47. https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Object.upload_file
  48. @param bucket: 存储桶名称-必须
  49. @param file_key: 需要上传文件路径+文件名称
  50. @param file_obj: 文件对象
  51. @param extra_args: 额外参数 如ACL配置
  52. @return: 当上传成功时为True;否则,False
  53. """
  54. try:
  55. session = self.session_conn
  56. bucket = session.Bucket(bucket)
  57. obj = bucket.Object(file_key)
  58. obj.upload_fileobj(file_obj, ExtraArgs=extra_args)
  59. return True
  60. except Exception as e:
  61. print(e.args)
  62. ex = traceback.format_exc()
  63. print('具体错误{}'.format(ex))
  64. return False
  65. def generate_file_obj_url(self, bucket, file_key):
  66. """
  67. 生成对象URL
  68. https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.generate_presigned_url
  69. @param bucket: 存储桶名称
  70. @param file_key: 文件名称
  71. @return: url
  72. """
  73. response_url = self.client_conn.generate_presigned_url(
  74. ClientMethod='get_object',
  75. Params={
  76. 'Bucket': bucket,
  77. 'Key': file_key
  78. }
  79. )
  80. return response_url
  81. def delete_obj(self, bucket, file_key):
  82. """
  83. 删除对象
  84. https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Object.delete
  85. @param bucket: 存储桶
  86. @param file_key: 文件名称
  87. @return: 当删除成功时为True;否则,False
  88. """
  89. try:
  90. bucket = self.session_conn.Bucket(bucket)
  91. obj = bucket.Object(file_key)
  92. obj.delete()
  93. return True
  94. except Exception as e:
  95. print(e.args)
  96. ex = traceback.format_exc()
  97. print('具体错误{}'.format(ex))
  98. return False
  99. def bucket_exists(self, bucket_name):
  100. """
  101. 判断桶是否存在,是否有访问权限
  102. @return: 当bucket存在时为True;否则,假的
  103. """
  104. try:
  105. self.client_conn.head_bucket(Bucket=bucket_name)
  106. exists = True
  107. except ClientError:
  108. exists = False
  109. return exists
  110. def get_object(self, bucket, key):
  111. """
  112. 获取对象
  113. @param bucket: 存储桶
  114. @param key: 文件
  115. @return : boolean
  116. """
  117. try:
  118. self.client_conn.get_object(Bucket=bucket, Key=key)
  119. return True
  120. except self.client_conn.exceptions.NoSuchKey:
  121. return False
  122. def download_object(self, bucket, key, file_name):
  123. """
  124. 下载对象至本地
  125. @param file_name: 保存位置以及名称
  126. @param bucket: 存储桶
  127. @param key: 文件
  128. @return : boolean
  129. """
  130. try:
  131. self.client_conn.download_file(bucket, key, file_name)
  132. return True
  133. except Exception as e:
  134. return e.args
  135. def copy_obj(self, source_bucket, to_bucket, file_key):
  136. """
  137. 复制对象
  138. @param source_bucket: 原存储桶
  139. @param file_key: 文件名称
  140. @param to_bucket: 新存储桶
  141. """
  142. source_dict = {
  143. 'Bucket': source_bucket,
  144. 'Key': file_key
  145. }
  146. self.session_conn.meta.client.copy(source_dict, to_bucket, file_key)
  147. def copy_single_obj(self, source_bucket, source_object, target_bucket, target_object, StorageClass=None):
  148. """
  149. 单个对象复制
  150. @param source_bucket:源存储桶
  151. @param source_object:源对象
  152. @param target_bucket:目标存储桶
  153. @param target_object:目标对象
  154. @param StorageClass:存储类
  155. @return: None
  156. """
  157. s3 = self.session_conn
  158. copy_source = {
  159. 'Bucket': source_bucket,
  160. 'Key': source_object
  161. }
  162. target_object = s3.Object(target_bucket, target_object)
  163. if StorageClass:
  164. target_object.copy_from(CopySource=copy_source, StorageClass=StorageClass)
  165. else:
  166. target_object.copy_from(CopySource=copy_source)
  167. def generate_put_obj_url(self, bucket_name, obj_key, storage_class=None):
  168. """
  169. 生成预签名对象URL
  170. @param bucket_name: 存储桶名称
  171. @param obj_key: 对象key
  172. @param storage_class: 存储类 例
  173. @return: 对象URL
  174. """
  175. params = {
  176. 'Bucket': bucket_name,
  177. 'Key': obj_key,
  178. }
  179. if storage_class:
  180. params['StorageClass'] = storage_class
  181. return self.session_conn.meta.client.generate_presigned_url('put_object',
  182. Params=params,
  183. ExpiresIn=7200)
  184. def batch_copy_obj(self, source_bucket, target_bucket, prefix, target_prefix, storage_class=None):
  185. """
  186. 批量拷贝对象
  187. @param source_bucket: 源存储桶
  188. @param target_bucket: 目标存储桶
  189. @param prefix: 需要搜索的对象前缀 例:AUS000247LTCLY/vod1/1686043996
  190. @param target_prefix: 目标对象前缀 例:app/algorithm-shop/1686043996
  191. @param storage_class: 存储类
  192. @return: None
  193. """
  194. s3 = self.session_conn
  195. # 遍历源存储桶中指定前缀下的所有对象,依次进行复制操作
  196. for obj in s3.Bucket(source_bucket).objects.filter(Prefix=prefix):
  197. key = obj.key # 对象键名
  198. target_key = f'{target_prefix}/' + key.split('/')[-1] # 新的对象键名,此处为 "new_path/" + 原有文件名
  199. copy_source = {
  200. 'Bucket': source_bucket,
  201. 'Key': key
  202. }
  203. # 将对象复制到目标存储桶,并设置存储类型和新的对象键名
  204. if storage_class:
  205. s3.Object(target_bucket, target_key).copy_from(CopySource=copy_source, StorageClass=storage_class)
  206. else:
  207. s3.Object(target_bucket, target_key).copy_from(CopySource=copy_source)
  208. def get_object_size(self, bucket_name, object_key):
  209. """
  210. 获取存储桶中指定对象的大小
  211. :param bucket_name: string,存储桶名称
  212. :param object_key: string,对象键名
  213. :return: int,指定对象的大小,单位为字节
  214. """
  215. s3 = self.session_conn
  216. obj = s3.Object(bucket_name, object_key)
  217. try:
  218. return obj.content_length
  219. except Exception as e:
  220. return 0
  221. def get_object_list(self, bucket_name, prefix):
  222. """
  223. 获取指定路径所有对象
  224. :param bucket_name: string,存储桶名称
  225. :param prefix: string,路径
  226. :return: int,指定对象的大小,单位为字节
  227. """
  228. try:
  229. s3 = self.client_conn
  230. obj = s3.list_objects_v2(Bucket=bucket_name, Prefix=prefix)
  231. return obj['Contents']
  232. except Exception as e:
  233. return []
  234. class RedisObject:
  235. def __init__(self, db=0):
  236. self.POOL = redis.ConnectionPool(host=SERVER_HOST, port=6379, db=db)
  237. self.CONN = redis.Redis(connection_pool=self.POOL)
  238. def set_data(self, key, val, expire=0):
  239. try:
  240. self.CONN.set(key, val)
  241. if expire > 0:
  242. self.CONN.expire(key, expire)
  243. except Exception as e:
  244. return False
  245. else:
  246. return True
  247. def get_data(self, key):
  248. try:
  249. val = self.CONN.get(key)
  250. except Exception as e:
  251. print(repr(e))
  252. return False
  253. else:
  254. if val:
  255. return val.decode('utf-8')
  256. else:
  257. return False
  258. def del_data(self, key):
  259. try:
  260. val = self.CONN.delete(key)
  261. except Exception as e:
  262. print(repr(e))
  263. return False
  264. else:
  265. return True
  266. def get_size(self):
  267. return self.CONN.dbsize()
  268. # 向列表插入数据
  269. def rpush(self, name, val):
  270. self.CONN.rpush(name, val)
  271. def lpop(self, name):
  272. val = self.CONN.lpop(name)
  273. if val:
  274. return val.decode('utf-8')
  275. else:
  276. return False
  277. # 获取列表长度
  278. def llen(self, name):
  279. return self.CONN.llen(name=name)
  280. # 获取列表所有数据
  281. def lrange(self, name, start, end):
  282. return self.CONN.lrange(name, start, end)
  283. # 删除列表指定数据
  284. def lrem(self, name, num, value):
  285. """
  286. num:列表方向,删除个数(0:所有)
  287. value:删除的值
  288. """
  289. return self.CONN.lrem(name, num, value)
  290. def get_ttl(self, key):
  291. ttl = self.CONN.ttl(key)
  292. if ttl:
  293. return ttl
  294. else:
  295. return 0
  296. def get_keys(self, key):
  297. keys = self.CONN.keys(key)
  298. if keys:
  299. return keys
  300. else:
  301. return False
  302. def set_ex_data(self, key, val, expire=0):
  303. try:
  304. self.CONN.setex(name=key, time=expire, value=val)
  305. except Exception as e:
  306. return False
  307. else:
  308. return True
  309. def set_hash_data(self, key, kwargs):
  310. self.CONN.hmset(key, kwargs)
  311. def get_hash_data(self, key, file):
  312. return self.CONN.hmget(key, file)
  313. def get_all_hash_data(self, key):
  314. return self.CONN.hgetall(key)
  315. class TokenObject:
  316. def __init__(self, token=None, returntpye='currency'):
  317. if token == 'local':
  318. token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySUQiOiIxNTg0MzUxODk2MjgyMTM4MDAxMzgwMDAiLCJsYW5nIjoiZW4iLCJ1c2VyIjoiMTM2ODAzMTc1OTYiLCJtX2NvZGUiOiIxMjM0MTMyNDMyMTQiLCJleHAiOjE1ODcyNzcwNjB9.c0LV_XyxwbzUlYqMJqx7vw9f19Jv-0kGnUHuu_go-mo'
  319. if token == 'test':
  320. token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiMTM4MDAxMzgwMDEiLCJleHAiOjE1Njk5OTg4OTYsInVzZXJJRCI6IjE1MTU2NDI2MjMzNzkzOTUxMzgwMDEzODAwMSIsImxhbmciOiJlbiIsIm1fY29kZSI6IjEyMzQxMzI0MzIxNCJ9.VAQtT9AbCCfXcrNj9DL5cvVasMDoI7AP8ptgU1GoMu8'
  321. self.token = token
  322. self.lang = None
  323. self.userID = None
  324. self.user = ''
  325. self.code = 0
  326. self.valid()
  327. self.returntpye = returntpye
  328. def valid(self):
  329. if self.token is None:
  330. self.code = 309
  331. return
  332. try:
  333. self.token = self.token.replace("Bearer ", "")
  334. res = jwt.decode(self.token, OAUTH_ACCESS_TOKEN_SECRET, algorithms='HS256')
  335. self.userID = res.get('userID', None)
  336. self.lang = res.get('lang', None)
  337. self.user = res.get('user', '')
  338. # 刷新登录时间
  339. # if self.userID:
  340. # print(self.user)
  341. # redisObj = RedisObject(db=3)
  342. # redisObj.set_data(key=self.userID, val=self.user, expire=300)
  343. except jwt.ExpiredSignatureError as e:
  344. self.code = 309
  345. return
  346. except Exception as e:
  347. self.code = 309
  348. return
  349. else:
  350. if not self.userID:
  351. self.code = 309
  352. return
  353. else:
  354. if self.userID:
  355. self.code = 0
  356. return res
  357. else:
  358. self.code = 309
  359. return
  360. def generate(self, data=None):
  361. if data is None:
  362. data = {}
  363. try:
  364. access_expire = int(OAUTH_ACCESS_TOKEN_TIME.total_seconds())
  365. refresh_expire = int(OAUTH_REFRESH_TOKEN_TIME.total_seconds())
  366. now_stamp = int(time.time())
  367. access_data = data
  368. refresh_data = data
  369. access_data['exp'] = access_expire + now_stamp
  370. refresh_data['exp'] = refresh_expire + now_stamp
  371. access_token = jwt.encode(access_data,
  372. OAUTH_ACCESS_TOKEN_SECRET,
  373. algorithm='HS256')
  374. refresh_token = jwt.encode(
  375. refresh_data,
  376. OAUTH_REFRESH_TOKEN_SECRET,
  377. algorithm='HS256')
  378. res = {
  379. 'access_token': access_token,
  380. 'access_expire': access_expire,
  381. 'refresh_expire': refresh_expire,
  382. 'refresh_token': refresh_token,
  383. }
  384. if self.returntpye == 'pc':
  385. res = {
  386. 'token': access_token,
  387. 'access_expire': access_expire,
  388. 'refresh_expire': refresh_expire,
  389. 'refresh_token': refresh_token,
  390. }
  391. except Exception as e:
  392. self.code = 309
  393. print(repr(e))
  394. else:
  395. self.code = 0
  396. return res
  397. def encryption(self, data=None):
  398. if data is None:
  399. data = {}
  400. try:
  401. access_expire = int(OAUTH_ACCESS_TOKEN_TIME.total_seconds())
  402. refresh_expire = int(OAUTH_REFRESH_TOKEN_TIME.total_seconds())
  403. now_stamp = int(time.time())
  404. access_data = data
  405. refresh_data = data
  406. access_data['exp'] = access_expire + now_stamp
  407. refresh_data['exp'] = refresh_expire + now_stamp
  408. access_token = jwt.encode(access_data,
  409. OAUTH_ACCESS_TOKEN_SECRET,
  410. algorithm='HS256')
  411. return access_token
  412. except Exception as e:
  413. self.code = 309
  414. print(repr(e))
  415. def refresh(self):
  416. if not self.token:
  417. self.code = 309
  418. return
  419. try:
  420. res = jwt.decode(self.token, OAUTH_REFRESH_TOKEN_SECRET, algorithms='HS256')
  421. except jwt.ExpiredSignatureError as e:
  422. print('过期')
  423. print(repr(e))
  424. self.code = 309
  425. except Exception as e:
  426. self.code = 309
  427. print(repr(e))
  428. else:
  429. self.code = 0
  430. userID = res.get('userID', '')
  431. user = res.get('user', '')
  432. lang = self.lang
  433. self.userID = userID
  434. self.user = user
  435. refreshRes = self.generate(data={'userID': userID, 'lang': lang, 'user': user})
  436. return refreshRes