class ServiceBase(object): dicConfig = config.CONF time = time datetime = datetime json = json hashlib = hashlib constants = Constants error_code = Code cache_key_predix = CacheKeyPredix properties = Properties() # redis = AsyncRedis() redis = RedisBase() httputils = HttpUtils date_utils = DateUtils common_utils = CommonUtil string_utils = StringUtils date_encoder = CJsonEncoder rsa_utils = RsaUtils excel_util = excel_util logger = Logs().logger language_code = {} # tornado_redis = TornadoRedis() def md5(self, text): """ md5加密 :param text: :return: """ result = hashlib.md5(text) return result.hexdigest() def import_model(self, model_name): """ 加载数据类 :param model_name: string 数据类名 :return: """ try: model = importlib.import_module('module.' + model_name) return model.Model() except Exception, e: print e return None
class LangManager: properties = Properties() lang_dict = {} def __init__(self): # 配置使用的语言 lang = self.properties.get('language', 'lang') lang = lang if lang else 'cn' # load model = importlib.import_module('language.' + lang) self.lang_dict = model.LangDict def get(self, key): """ :param key: :return: """ return self.lang_dict[key] if key in self.lang_dict else ''
class ServiceBase(object): dicConfig = config.CONF time = time datetime = datetime json = json hashlib = hashlib constants = Constants error_code = Code cache_key_predix = CacheKeyPredix properties = Properties() redis = AsyncRedis() httputils = HttpUtils date_utils = DateUtils common_utils = CommonUtil string_utils = StringUtils money_utils = MoneyUtils date_encoder = CJsonEncoder rsa_utils = RsaUtils excel_util = excel_util logger = Logs().logger lang = LangManager() power_tree = [] task = task schedule = schedule # tornado_redis = TornadoRedis() def md5(self, text): """ md5加密 :param text: :return: """ result = hashlib.md5(text.encode(encoding='utf-8')) return result.hexdigest() def sha1(self, text): """ sha1生成签名 :param text: :return: """ result = hashlib.sha1(text.encode(encoding='utf-8')) return result.hexdigest() def import_model(self, model_name): """ 加载数据类 :param model_name: string 数据类名 :return: """ try: model = importlib.import_module('module.' + model_name) return model.Model() except Exception as e: self.logger.exception(e) return None def time_to_mktime(self, time_str, format_str): """ 将时间字符串转化成时间戳 :param params: :return: """ return time.mktime(time.strptime(time_str, format_str)) def salt(self, salt_len=6, is_num=False, chrset=''): """ 密码加密字符串 生成一个固定位数的随机字符串,包含0-9a-z @:param salt_len 生成字符串长度 """ if is_num: chrset = '0123456789' else: if not chrset: chrset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ' salt = [] for i in range(salt_len): item = random.choice(chrset) salt.append(item) return ''.join(salt) def create_uuid(self): """ 创建随机字符串 :return: """ text = str(time.time()) + self.salt(12) m = hashlib.md5() m.update(bytes(text.encode(encoding='utf-8'))) return m.hexdigest() def loads_list(self, list_str): """ 转换字符串成列表 :param list_str: :return: create:wsy 2017/7/31 """ try: data_list = self.json.loads(list_str) except Exception as e: self.logger.exception(e) data_list = [] return data_list def loads_dic(self, dic_str): """ 转换字符串成字典 :param dic_str: :return: create:wsy 2017/7/31 """ try: data_dic = self.json.loads(dic_str) except Exception as e: self.logger.exception(e) data_dic = {} return data_dic def escape_string(self, data, un=None): """ 特殊字符转义 :param data: string, tuple, list, dict 转义数据 :param un: :return: """ if isinstance(data, str): return tornado.escape.xhtml_escape( data) if not un else tornado.escape.xhtml_unescape(data) elif isinstance(data, tuple) or isinstance(data, list): lisData = [] for item in data: lisData.append( tornado.escape.xhtml_escape(str(item)) if not un else tornado.escape.xhtml_unescape(str(item))) return lisData elif isinstance(data, dict): for key in data: data[key] = tornado.escape.xhtml_escape(str( data[key])) if not un else tornado.escape.xhtml_unescape( str(data[key])) return data def do_service(self, service_path, method, params={}): """ 调用服务 :param service_path: :param method: :param params: :return: """ return serviceManager.do_service(service_path, method, params=params, version=config.CONF['version'], power=self.power_tree) def sign_params(self, params, secret_key): """ 验签 :param params: :param secret_key: :return: """ params_keys = [] for (k, v) in params.items(): if k != 'sign': params_keys.append(k) params_string = '' for key in sorted(params_keys): params_string += (key + '=' + params[key] + '&') params_string = self.md5(params_string + secret_key).upper() return params_string == params['sign'].upper() @tornado.gen.coroutine def load_extensions(self, trigger_position, data): """ 加载扩展程序 :param trigger_position: :param data: :return: """ data['trigger_position'] = trigger_position result = yield self.do_service('cfg.extensions.service', 'query', {'trigger_position': trigger_position}) if result and 'code' in result and result['code'] == 0: # 发送消息 for item in result['data']: service_path = item['package_path'] method = item['method'] # self.publish_message(service_path, method, data) yield self.task.add(service_path, method, data) def _e(self, error_key): """ :param error_key: :return: """ data = {} for key in self.error_code[error_key]: data[key] = self.error_code[error_key][key] # if error_key in self.language_code: # data['msg'] = self.language_code[error_key] return data def _gre(self, data): """ tornado.gen.Return :rtype: :param data: 数据 :return: """ return tornado.gen.Return(self._e(data)) def _gree(self, error_key, customer_msg): """ 自定义扩展错误信息 :param error_key: :param customer_msg: 自定义额外错误信息 :return: """ result = self._e(error_key) if customer_msg: result['msg'] += '({})'.format(customer_msg) return tornado.gen.Return(result) def _grs(self, data={}): """ 成功返回 :param data: :return: """ result = self._e('SUCCESS') result['data'] = data return tornado.gen.Return(result) def _gr(self, data): """ tornado.gen.Return :param data: 数据 :return: """ return tornado.gen.Return(data) @tornado.gen.coroutine def cache_get(self, key): result = yield self.redis.get(key) if result: expire = yield self.redis.ttl(key) if expire < int( self.properties.get('expire', 'CACHE_REFRESH_EXPIRE')): yield self.redis.expire( key, self.properties.get('expire', 'CACHE_EXPIRE')) try: result = json.loads(result) except Exception as e: yield self.redis.expire(key, 0) result = False return result else: return False @tornado.gen.coroutine def cache_set(self, key, value): try: value = json.dumps(value, cls=self.date_encoder) yield self.redis.set(key, value) yield self.redis.expire( key, self.properties.get('expire', 'CACHE_EXPIRE')) return True except Exception: return False def get_path(self, data, power_path_list=None): """ 1 遍历用户权限树,如果有child,获得child的path,如果没有,返回power['path'] 2 递归的遍历child获得path,直到所有child为空 3 将所有path加载到power_tree 列表中 :param data: 用户权限树 :return: """ if power_path_list is None: power_path_list = [] for power in data: power_path_list.append(str(power['path'])) if power['child']: self.get_path(power['child'], power_path_list) # else: # power_path_list.append(str(power['path'])) return power_path_list @classmethod def params_set(cls, model=None, data=None): """ 数据对象设置 :param model: :param data: :return: """ def decorate(func): @wraps(func) @tornado.gen.coroutine def wrapper(*args, **kwargs): o = args[0] params = args[1] model_data = None if hasattr(o, model): model_obj = getattr(o, model) if hasattr(model_obj, data): model_data = getattr(model_obj, data) new_args = args if model_data: if isinstance(params, dict): model_data.update(params) new_args = (args[0], model_data) result = yield func(*new_args, **kwargs) return result return wrapper return decorate
import json import random from tools.logs import Logs from tools.date_json_encoder import CJsonEncoder from tools.date_utils import DateUtils from source.async_redis import AsyncRedis from source.async_model import AsyncModelBase # from source.redisbase import RedisBase from source.properties import Properties from .report import Report import sys import traceback logger = Logs().logger properties = Properties('task') redis = AsyncRedis() date_utils = DateUtils() task_queue = properties.get('cache', 'task_queue') failed_queue = properties.get('cache', 'failed_queue') loop_num = int(properties.get('task', 'task_num')) server_key = properties.get('cache', 'servers') server_coroutine_key = properties.get('cache', 'server_coroutine') async def save_to_db(task_unique_id, service_path, method, params_json): """ 保存任务到DB :param task_unique_id: :param service_path:
@time: 2018/6/5 10:59 """ import json from tools.logs import Logs from tools.date_json_encoder import CJsonEncoder from tools.date_utils import DateUtils from source.async_redis import AsyncRedis # from source.redisbase import RedisBase from source.properties import Properties from .report import Report import sys import traceback logger = Logs().logger properties = Properties('task') redis = AsyncRedis() date_utils = DateUtils() task_queue = properties.get('cache', 'task_queue') failed_queue = properties.get('cache', 'failed_queue') loop_num = int(properties.get('task', 'task_num')) async def add(path='', method='', arguments=None, is_priority=False, sub_task=None): """ 添加任务
import time import threadpool import conf.config as config from constants.cachekey_predix import CacheKeyPredix as cachekey from source.redisbase import RedisBase from source.service_manager import ServiceManager from tools.schedule_utils import ScheduleUtils from tools.date_json_encoder import CJsonEncoder from source.properties import Properties from source.model import ModelBase from tools.date_utils import DateUtils import traceback from tools.logs import Logs properties = Properties() pool_size = 3 try: pool_size = int(properties.get('task', 'POOL_NUM')) except Exception, e: print e redis = RedisBase() task_redis = redis.get_conn() error_redis = redis.get_conn() cache_key = cachekey.TASK_DATA_LIST error_cache_key = cachekey.ERROR_TASK_DATA_LIST pool = threadpool.ThreadPool(pool_size) service_manager = ServiceManager() config = config
class Base(Controller): json = json time = time logged_user = {} # redis = RedisBase() redis = AsyncRedis() user_data = {} buyer_user_data = {} version = config.CONF['version'] cache_key_pre = CacheKeyPredix error_code = Code constants = Constants properties = Properties() logger = Logs().logger auth = None shop_id = '0' _params = {} power_tree = [] # def initialize(self): # """ # 初始化 # 初始化数据类 # """ # # Controller.config = config.CONF # # Controller.initialize(self) # # # self.view_data['title'] = self.config['title'] # # # 访问者身份标识 # # self.get_user_unique_code() # # self._params = self.get_params() @tornado.gen.coroutine def prepare(self): """ 接受请求前置方法 1.解析域名 2.检查IP限制 3.权限检查 :return: """ # 访问者身份标识 self.get_user_unique_code() self._params = self.get_params() # user_data_dict = yield self.__get_login_user_data() # # 1. # yield self.get_shop_host(self.request.host) # 2.检查IP限制 # intercept_status = yield self.intercept_ip(user_data_dict) # if not intercept_status: # self.finish() # 3. if self.auth: if self.auth[0] is not None: auth_status = yield self.auth_check(user_data_dict) if not auth_status: self.finish() # 刷新token yield self.refresh_token() @tornado.gen.coroutine def intercept_ip(self, user_data_dict): """ 拦截IP 对C端拦截,B端不拦截 1. 检查登录用户信息,如果有商户信息,所有请求不检查IP拦截 2. 调用服务计算拦截 :return: """ # 判断是否有seller信息,如果有不检查IP seller_data = user_data_dict.get('seller', {}) if seller_data: raise self._gr(True) # 调用IP拦截service result = yield self.do_service( 'system.ip_country.service', 'intercept', { 'shop_id': self._params.get('shop_id', ''), 'ip': self.request.remote_ip }) if result['code'] != 0: self.error_out(result) raise self._gr(False) raise self._gr(True) @tornado.gen.coroutine def auth_check(self, user_data_dict): """ 登录认证 根据控制器的权限设置,调用不同的权限检查 """ # # 1.获取登录用户信息 # user_data_dict = yield self.__get_login_user_data() auth = self.auth # 如果没有设置权限,返回 if not auth or not auth[0]: raise self._gr(True) is_auth_error = False is_login = True is_auth = True power_group = auth[0] no_check_control = auth[1] if len(auth) > 1 else False # 2.根据控制器设置,进行检查 for group in power_group: if group == 'buyer': # 买家 user_data = user_data_dict.get('buyer', {}) if user_data: if 'user_type' not in user_data: is_login = False continue if user_data['user_type'] not in self.auth[0]: is_auth = False continue # 判断是否开始平台化,如果未开始,执行店铺检查 is_platform = self.properties.get('base', 'IS_PLATFORM') if is_platform == 'False' and str( user_data.get('shop_id', '0')) != str( self.params('shop_id')): is_login = False continue is_login = True is_auth = True break else: is_login = False continue elif group == 'admin' or group == 'seller': # 商户 user_data = user_data_dict.get('seller', {}) if not user_data: is_login = False continue if 'user_type' not in user_data: is_login = False continue if user_data['user_type'] not in self.auth[0]: is_auth = False continue check_power_result = yield self.__check_power( user_data, no_check_control) if not check_power_result: raise self._gr(False) is_login = True is_auth = True break elif group == 'platform': # 三方平台 user_data = yield self.sign_auth_platform() if not user_data: is_auth = False continue if 'user_type' not in user_data: is_login = False continue if user_data['user_type'] not in self.auth[0]: is_auth = False continue self.user_data = user_data is_login = True is_auth = True break else: is_auth_error = True self.logger.exception('auth error') break if is_auth_error: self.error_out(self._e('AUTH_SET_ERROR')) raise self._gr(False) if not is_login: self.error_out(self._e('NOT_LOGIN')) raise self._gr(False) if not is_auth: self.error_out(self._e('AUTH_ERROR')) raise self._gr(False) raise self._gr(True) @tornado.gen.coroutine def __get_login_user_data(self): """ 获取用户的登录信息 :return: """ result = {} # 买家 buyer_token = self.params('buyer_token') if self.params( 'buyer_token') else self.get_cookie('buyer_token') if buyer_token: cache_key = self.cache_key_pre.BUYER_TOKEN + self.md5(buyer_token) user_data = yield self.redis.hgetall(cache_key) self.buyer_user_data = user_data result['buyer'] = user_data # 商户 sign = self.params('sign') if sign: sign_token = yield self.sign_login() if not sign_token: token = self.params('token') if self.params( 'token') else self.get_cookie('token') else: token = sign_token else: token = self.params('token') if not token: token = self.get_cookie('token') if token: cache_key = self.cache_key_pre.ADMIN_TOKEN + self.md5(token) user_data = yield self.redis.hgetall(cache_key) self.user_data = user_data result['seller'] = user_data raise self._gr(result) @tornado.gen.coroutine def __check_power(self, user_data, no_check_control): """ 检查权限 :param user_data: :param no_check_control: :return: """ # 1 获取店铺权限 # 2 group_id=0 超级管理员,查看用户请求power是否符合店铺权限 # 3 group_id>0 普通管理员,查看用户请求power是否符合普通用户权限(shop_id) if not no_check_control: # 获取前端请求uri,替换api全段字段,用户请求权限 base_url_prefix = self.properties.get('base', 'BASE_URL_PREFIX')\ .replace('BASE_URL_PREFIX=', '').replace('\n', '') power = self.request.uri.replace(base_url_prefix, '') if 'group_id' in user_data and int(user_data['group_id']) >= 0: auth_error_flag = True # 管理员menu(每个用户真正的权限树,不管是超级管理员,还是普通管理员) menu_params = { 'shop_id': user_data['shop_id'], 'group_id': user_data['group_id'], } menu_result = yield self.do_service('user.auth.menu.service', 'query_menu', params=menu_params) if menu_result['code'] != 0: raise self._gr(menu_result) shop_power = self.get_path(menu_result['data']) # 检查请求url的power是否匹配用户权限树shop_power for power_tree in shop_power: # 用shop_power 匹配 power # shop_power: /user/auth/power # power: /user/auth/power/query pattern = re.compile(power_tree) if pattern.match(power): auth_error_flag = False break # 检查权限 if auth_error_flag: self.error_out(self._e('AUTH_ERROR')) raise self._gr(False) else: self.error_out(self._e('AUTH_ERROR')) raise self._gr(False) raise self._gr(True) @tornado.gen.coroutine def create_token(self, params, user_type, expire=None): """ 创建token和cookie :param params: :param user_type: :param expire: :return: """ if not user_type: raise self._gr({'code': -1, 'msg': ''}) # 处理domain request = self.request host = request.host host_port = host.split(':') hosts = host_port[0].split('.') if self.properties.get('domain', 'base'): domain_base = self.properties.get('domain', 'base') else: domain_base = '.'.join(hosts[-2:]) # 根据用户类型,生成缓存KEY if user_type == 'admin': token = self.cache_key_pre.ADMIN_TOKEN + self.salt(salt_len=32) cache_key = self.cache_key_pre.ADMIN_TOKEN + self.md5(token) expire = expire if expire else int( self.properties.get('expire', 'ADMIN_EXPIRE')) cookie_key = 'token' params['user_type'] = self.constants.ADMIN_TYPE elif user_type == 'buyer': token = self.cache_key_pre.BUYER_TOKEN + self.salt(salt_len=32) cache_key = self.cache_key_pre.BUYER_TOKEN + self.md5(token) expire = expire if expire else int( self.properties.get('expire', 'BUYER_EXPIRE')) cookie_key = 'buyer_token' params['user_type'] = self.constants.BUYER_TYPE else: raise self._gr({'code': -1, 'msg': ''}) # 创建缓存 yield self.redis.hmset(cache_key, params) # 设置cookie if 'remember' in params and params['remember'] == '1': yield self.redis.expire( cache_key, int(self.properties.get('expire', 'ADMIN_EXPIRE_REMEMBER'))) self.set_cookie( cookie_key, token, expires=time.time() + int(self.properties.get('expire', 'ADMIN_EXPIRE_REMEMBER')), domain=domain_base) else: yield self.redis.expire(cache_key, expire) self.set_cookie(cookie_key, token, domain=domain_base) raise self._gr({'code': 0, 'token': token}) @tornado.gen.coroutine def refresh_token(self): """ 刷新token :return: """ auth = self.auth # 如果没有设置权限,返回 if not auth or not auth[0]: raise self._gr(True) power_group = auth[0] for group in power_group: if group == 'buyer': # 买家 buyer_token = self.params('buyer_token') if not buyer_token: buyer_token = self.get_cookie('buyer_token') if not buyer_token: continue cache_key = self.cache_key_pre.BUYER_TOKEN + self.md5( buyer_token) expire = int(self.properties.get('expire', 'BUYER_EXPIRE')) refresh_expire = int( self.properties.get('expire', 'BUYER_REFRESH_EXPIRE')) self.__refresh_token_update(cache_key, expire, refresh_expire) elif group == 'admin' or group == 'seller': token = self.params('token') if not token: token = self.get_cookie('token') if not token: continue if self.params('sign'): shop_id = self.params('shop_id') token = 'sign:' + shop_id cache_key = self.cache_key_pre.ADMIN_TOKEN + self.md5(token) expire = int(self.properties.get('expire', 'ADMIN_EXPIRE')) refresh_expire = int( self.properties.get('expire', 'ADMIN_REFRESH_EXPIRE')) self.__refresh_token_update(cache_key, expire, refresh_expire) @tornado.gen.coroutine def __refresh_token_update(self, cache_key, expire, refresh_expire): """ 更新token有效期 :param cache_key: :param expire: :param refresh_expire: :return: """ if cache_key and expire and refresh_expire: cache_data = yield self.redis.ttl(cache_key) if cache_data: left_seconds = int(cache_data) # 获取用户登录数据 # self.user_data = yield self.redis.hgetall(cache_key) if (expire - left_seconds) >= refresh_expire: # 如果token的总生命秒数 - 剩余生命秒数 >= 刷新秒数,则重新设置token的生命秒数 yield self.redis.expire(cache_key, expire) @tornado.gen.coroutine def sign_login(self): """ 签名登录 1.验签 2.验签通过,检查缓存是否有值 ,有值 直接返回真 3.如果没值,生成缓存 :return: """ # 验签 sign = self.params('sign') sing_result = yield self.do_service('user.auth.sign.service', 'sign_login', self.params()) if sing_result['code'] != 0: raise self._gr(False) # 检查缓存是否有值 shop_id = self.params('shop_id') token = 'sign:' + shop_id cache_key = self.cache_key_pre.ADMIN_TOKEN + self.md5(token) user_data = yield self.redis.hgetall(cache_key) if user_data: raise self._gr(token) # 创建缓存 yield self.redis.hmset( cache_key, { 'shop_id': shop_id, 'user_type': self.constants.SELLER_TYPE, 'admin_id': -1, 'group_id': 0 }) # 设置cookie expire = int(self.properties.get('expire', 'ADMIN_EXPIRE')) yield self.redis.expire(cache_key, expire) raise self._gr(token) @tornado.gen.coroutine def sign_auth_platform(self): """ 平台授权认证 1.检查token参数,如果有token,根据token获取缓存数据,没有token或缓存数据不存在,进行验签 2.验签,检查sign参数,如果没有,返回授权失败,有,进行验签 3.创建登录缓存,返回登录信息及token :return: """ # 1. token = self.params('token') if token: cache_key = self.cache_key_pre.PLATFORM_TOKEN + token user_data = yield self.redis.hgetall(cache_key) if user_data: raise self._gr(user_data) # 2. # psign 为 platform 验签的 sign psign = self.params('psign') if not psign: raise self._gr(False) sing_result = yield self.do_service('user.auth.sign.service', 'sign_auth_platform', self.params()) if sing_result['code'] != 0: raise self._gr(False) # 3. app_id = self.params('app_id') token = self.md5('sign:' + app_id) cache_key = self.cache_key_pre.PLATFORM_TOKEN + token user_data = { 'app_id': app_id, 'user_type': self.constants.PLATFORM_TYPE, 'token': token, 'admin_id': -1, 'shop_id': app_id } yield self.redis.hmset(cache_key, user_data) expire = int(self.properties.get('expire', 'ADMIN_EXPIRE')) yield self.redis.expire(cache_key, expire) raise self._gr(user_data) @tornado.gen.coroutine def get_user_data(self): user_data = None params = self.params() if self.get_cookie('buyer_token'): cache_key = self.cache_key_pre.BUYER_TOKEN + self.md5( self.get_cookie('buyer_token')) user_data = yield self.redis.hgetall(cache_key) elif self.get_cookie('token'): cache_key = self.cache_key_pre.ADMIN_TOKEN + self.md5( self.get_cookie('token')) user_data = yield self.redis.hgetall(cache_key) if 'sign' in params: user_data = yield self.sign_auth_platform() raise self._gr(user_data) def md5(self, text): """ MD5加密 @:param text 需加密字符串 @return 加密后字符串 """ result = hashlib.md5(text.encode('utf-8')) return result.hexdigest() def create_uuid(self): """ 声称随机字符串 :return: """ m = hashlib.md5() m.update(bytes(str(time.time()), encoding='utf-8')) return m.hexdigest() def sha1(self, text): """ sha1 加密 @:param text 需加密字符串 @return 加密后字符串 """ return hashlib.sha1(text).hexdigest() def salt(self, salt_len=6, is_num=False): """ 密码加密字符串 生成一个固定位数的随机字符串,包含0-9a-z @:param salt_len 生成字符串长度 """ if is_num: chrset = '0123456789' else: chrset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ' salt = [] for i in range(salt_len): item = random.choice(chrset) salt.append(item) return ''.join(salt) def out(self, data): """ 输出结果 :param data: 返回数据字典 """ self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(self.json.dumps(data, cls=CJsonEncoder)) def error_out(self, error, data=''): """ 错误输出 :param error: 错误信息对象 :param data: 返回数据字典 :return: """ out = error if data: out['data'] = data self.write(out) def clear_template_cache(self): """ 清除模板缓存 """ self._template_loaders.clear() @tornado.gen.coroutine def get(self): """ 重写父类get方法,接受GET请求 如果执行到此方法,说明请求类型错误 """ self.error_out(self._e('REQUEST_TYPE_ERROR')) @tornado.gen.coroutine def post(self): """ 重写父类post方法,接受POST请求 如果执行到此方法,说明请求类型错误 """ self.error_out(self._e('REQUEST_TYPE_ERROR')) @tornado.gen.coroutine def get_shop_host(self, host): """ 根据自定义域名/二级域名获取店铺ID 规则: 1. 检查访问无名是否为系统域名或其二级域名,是使用二级域名,不是使用自定义域名 2. 根据二级域名或自定义域名获取店铺ID(有缓存策略) 3. 将shop_id赋值给上下文对象 :param host: :return: """ is_use_domain = self.properties.get('domain', 'is_use') domain_base = self.properties.get('domain', 'base') if host and is_use_domain == 'True': site_domain = '' # 1 if domain_base in host: # site_domain = host hosts = host.split('.') if len(hosts) > 1 and hosts[0] != 'www' and hosts[ 0] != 'wxauth' and hosts[0] != 'api': site_domain = hosts[0] else: # hosts = host.split('.') # if len(hosts) > 1 and hosts[0] != 'www' and hosts[0] != 'wxauth' and hosts[0] != 'api': # site_domain = hosts[0] hosts = host.split(':') site_domain = hosts[0] if site_domain: # 2 result = yield self.do_service('channel.shop.service', 'query_shop_domain', {'domain': site_domain}) if result and result['code'] == 0: shop_id = result['data']['shop_id'] if shop_id: self.shop_id = shop_id # 给参数对象添加shop_id # params = self.params() # 3 self._params['shop_id'] = shop_id def do_service(self, service_path, method, params={}): """ 调用服务 :param service_path: :param method: :param params: :return: """ token = self.get_cookie('token') buyer_token = self.get_cookie('buyer_token') language = self.get_cookie('language') if not token: token = self.params('token') if not buyer_token: buyer_token = self.params('buyer_token') if not language: language = self.params('language') # 从application.settings导入power_tree power_tree = self.settings['power_tree'] # params['token'] = token if token else '' # params['buyer_token'] = buyer_token if buyer_token else '' # params['language'] = language if language else 'cn' return serviceManager.do_service(service_path, method, params=params, version=config.CONF['version'], power=power_tree) def get_user_unique_code(self): """ 创建访问者唯一身份标识 :return: """ cookie_name = 'unique_code' unique_code = self.get_cookie(cookie_name) if not unique_code: unique_code = self.params('unique_code') if not unique_code: unique_code = self.salt(32) self.set_cookie(cookie_name, unique_code) return unique_code def _e(self, error_key): """ :param error_key: :return: """ # language = self.get_cookie('language') # if not language: # language = self.params('language') # language = language if language else 'cn' # language_module = self.importlib.import_module('language.' + language).Code data = {} for key in self.error_code[error_key]: data[key] = self.error_code[error_key][key] # if error_key in language_module: # data['msg'] = language_module[error_key] return data def _gr(self, data): """ tornado.gen.Return :param data: 数据 :return: """ return tornado.gen.Return(data) def params(self, key=''): """ 获取参数中指定key的数据 :param key: :return: """ if not key: return self._params elif key not in self._params: return '' else: return self._params[key] def get_user_agent(self): """ 获取用户访问数据 :return: """ request = self.request if 'Remote_ip' in request.headers and request.headers['Remote_ip']: ip = request.headers['Remote_ip'] elif 'X-Forward-For' in request.headers and request.headers[ 'X-Forward-For']: ip = request.headers['X-Forward-For'] else: ip = request.remote_ip cookies = '' if request.cookies: for k, v in request.cookies.items(): cookies += k + '=' + v.value + ';' try: user_agent = request.headers['User-Agent'] except Exception as e: user_agent = '' return { 'user_unique_code': self.get_user_unique_code(), 'remote_ip': ip, 'user_agent': user_agent, 'cookies': cookies } def get_path(self, data, power_path_list=None): """ 1 遍历用户权限树,如果有child,获得child的path,如果没有,返回power['path'] 2 递归的遍历child获得path,直到所有child为空 3 将所有path加载到power_tree 列表中 4 获取子路径 :param data: 用户权限树 :return: """ if power_path_list is None: power_path_list = [] for power in data: power_path_list.append(str(power['path'])) if power['child']: self.get_path(power['child'], power_path_list) # else: # power_path_list.append(str(power['path'])) return power_path_list
# -*- coding:utf-8 -*- """ 同步数据类 """ # import MySQLdb import pymysql from DBUtils.PooledDB import PooledDB from source.properties import Properties from source.sql_builder import SqlBuilder from source.sql_constants import SqlConstants from source.sql_builder_orm import SqlBuilderOrm from tools.logs import Logs properties = Properties() class ModelBase(SqlBuilder): """ 数据类 """ sql_constants = SqlConstants pool = PooledDB(creator=pymysql, mincached=1, maxcached=5, blocking=True, reset=True, host=properties.get('jdbc', 'DB_HOST'), user=properties.get('jdbc', 'DB_USER'), passwd=properties.get('jdbc', 'DB_PASS'), db=properties.get('jdbc', 'DB_BASE'),
from base.service import ServiceBase from source.async_model import AsyncModelBase from source.async_redis import AsyncRedis from tools.date_json_encoder import CJsonEncoder from tools.date_utils import DateUtils from tools.logs import Logs from tools.cron_utils import CronUtils from source.properties import Properties from task.schedule.path_conf import CONF import task # redis = RedisBase() redis = AsyncRedis() logger = Logs().logger cron_utils = CronUtils() properties = Properties('schedule') intervals = int(properties.get('schedule', 'intervals')) run_time = int(properties.get('schedule', 'run_time')) SCHEDULE_KEY = properties.get('schedule', 'schedule_key') JOB_KEY = properties.get('schedule', 'job_key') key_YYMMDDHHMM = '%Y%m%d%H%M' key_YYMMDDHHMMSS = '%Y%m%d%H%M%S' async def do_job_list(job_list, is_normal=True): """ 开协程执行定时任务 job_list 需要执行的任务列表 is_normal 是否正常执行任务 True正常任务 , False 过期任务补偿执行 :return:
class Base(Controller): json = json time = time logged_user = {} redis = RedisBase() # redis = AsyncRedis() user_data = {} buyer_user_data = {} version = config.CONF['version'] cache_key_pre = CacheKeyPredix error_code = Code constants = Constants properties = Properties() logger = Logs().logger auth = None shop_id = '0' _params = {} # def initialize(self): # """ # 初始化 # 初始化数据类 # """ # # Controller.config = config.CONF # # Controller.initialize(self) # # # self.view_data['title'] = self.config['title'] # # # 访问者身份标识 # # self.get_user_unique_code() # # self._params = self.get_params() @tornado.gen.coroutine def prepare(self): """ 接受请求前置方法 1.解析域名 2.权限检查 :return: """ # 访问者身份标识 self.get_user_unique_code() self._params = self.get_params() yield self.get_shop_host(self.request.host) if self.auth: if self.auth[0] is not None: auth_status = yield self.auth_check() if not auth_status: self.finish() # 刷新token yield self.refresh_token() @tornado.gen.coroutine def auth_check(self): """ 登录认证 根据控制器的权限设置,调用不同的权限检查 """ auth = self.auth # 如果没有设置权限,返回 if not auth or not auth[0]: raise self._gr(True) is_auth_error = False is_login = True is_auth = True power_group = auth[0] for group in power_group: if group == 'buyer': # 买家 buyer_token = self.params('buyer_token') if not buyer_token: buyer_token = self.get_cookie('buyer_token') if not buyer_token: is_login = False break cache_key = self.cache_key_pre.BUYER_TOKEN + self.md5( buyer_token) user_data = self.redis.hgetall(cache_key) self.buyer_user_data = user_data elif group == 'admin' or group == 'seller': sign = self.params('sign') if sign: sign_token = yield self.sign_login() if not sign_token: token = self.params('token') if not token: token = self.get_cookie('token') if not token: is_login = False break else: token = sign_token else: token = self.params('token') if not token: token = self.get_cookie('token') if not token: is_login = False break cache_key = self.cache_key_pre.ADMIN_TOKEN + self.md5(token) user_data = self.redis.hgetall(cache_key) self.user_data = user_data else: is_auth_error = True self.logger.exception('auth error') break if not user_data: is_login = False break if 'user_type' not in user_data: is_login = False break if user_data['user_type'] not in self.auth[0]: is_auth = False break if is_auth_error: self.error_out(self._e('AUTH_SET_ERROR')) raise self._gr(False) if not is_login: self.error_out(self._e('NOT_LOGIN')) raise self._gr(False) if not is_auth: self.error_out(self._e('AUTH_ERROR')) raise self._gr(False) raise self._gr(True) @tornado.gen.coroutine def create_token(self, params, user_type, expire=None): """ 创建token和cookie :param params: :param user_type: :param expire: :return: """ if not user_type: raise self._gr({'code': -1, 'msg': ''}) # 处理domain request = self.request host = request.host host_port = host.split(':') hosts = host_port[0].split('.') domain_base = '.'.join(hosts[-2:]) # 根据用户类型,生成缓存KEY if user_type == 'admin': token = self.cache_key_pre.ADMIN_TOKEN + self.salt(salt_len=32) cache_key = self.cache_key_pre.ADMIN_TOKEN + self.md5(token) expire = expire if expire else int( self.properties.get('expire', 'ADMIN_EXPIRE')) cookie_key = 'token' params['user_type'] = self.constants.ADMIN_TYPE elif user_type == 'buyer': token = self.cache_key_pre.BUYER_TOKEN + self.salt(salt_len=32) cache_key = self.cache_key_pre.BUYER_TOKEN + self.md5(token) expire = expire if expire else int( self.properties.get('expire', 'BUYER_EXPIRE')) cookie_key = 'buyer_token' params['user_type'] = self.constants.BUYER_TYPE else: raise self._gr({'code': -1, 'msg': ''}) # 创建缓存 self.redis.hmset(cache_key, params) # 设置cookie if 'remember' in params and params['remember'] == '1': self.redis.expire( cache_key, int(self.properties.get('expire', 'ADMIN_EXPIRE_REMEMBER'))) self.set_cookie( cookie_key, token, expires=time.time() + int(self.properties.get('expire', 'ADMIN_EXPIRE_REMEMBER')), domain=domain_base) else: self.redis.expire(cache_key, expire) self.set_cookie(cookie_key, token, domain=domain_base) raise self._gr({'token': token}) @tornado.gen.coroutine def refresh_token(self): """ 刷新token :return: """ auth = self.auth # 如果没有设置权限,返回 if not auth or not auth[0]: raise self._gr(True) cache_key = '' expire = '' refresh_expire = '' power_group = auth[0] for group in power_group: if group == 'buyer': # 买家 buyer_token = self.params('buyer_token') if not buyer_token: buyer_token = self.get_cookie('buyer_token') if not buyer_token: break cache_key = self.cache_key_pre.BUYER_TOKEN + self.md5( buyer_token) expire = int(self.properties.get('expire', 'BUYER_EXPIRE')) refresh_expire = int( self.properties.get('expire', 'BUYER_REFRESH_EXPIRE')) elif group == 'admin' or group == 'seller': token = self.params('token') if not token: token = self.get_cookie('token') if not token: break if self.params('sign'): shop_id = self.params('shop_id') token = 'sign:' + shop_id # cache_key = self.cache_key_pre.ADMIN_TOKEN + self.md5(token) cache_key = self.cache_key_pre.ADMIN_TOKEN + self.md5(token) expire = int(self.properties.get('expire', 'ADMIN_EXPIRE')) refresh_expire = int( self.properties.get('expire', 'ADMIN_REFRESH_EXPIRE')) if cache_key and expire and refresh_expire: cache_data = self.redis.ttl(cache_key) if cache_data: left_seconds = int(cache_data) # 获取用户登录数据 self.user_data = self.redis.hgetall(cache_key) if (expire - left_seconds) >= refresh_expire: # 如果token的总生命秒数 - 剩余生命秒数 <= 刷新秒数,则重新设置token的生命秒数 self.redis.expire(cache_key, expire) @tornado.gen.coroutine def sign_login(self): """ 签名登录 1.检查缓存是否有值,有值直接返回真 2.如果没值,调用验签服务进行验签 3.验签通过,生成缓存 :return: """ # 检查缓存是否有值 shop_id = self.params('shop_id') token = 'sign:' + shop_id cache_key = self.cache_key_pre.ADMIN_TOKEN + self.md5(token) user_data = self.redis.hgetall(cache_key) if user_data: raise self._gr(token) sign = self.params('sign') sing_result = yield self.do_service('user.auth.sign.service', 'sign_login', self.params()) if sing_result['code'] != 0: raise self._gr(False) # 创建缓存 self._params['sign'] = sign self.redis.hmset( cache_key, { 'shop_id': shop_id, 'user_type': self.constants.SELLER_TYPE, 'admin_id': -1, 'group_id': 0 }) # 设置cookie expire = int(self.properties.get('expire', 'ADMIN_EXPIRE')) self.redis.expire(cache_key, expire) raise self._gr(token) def md5(self, text): """ MD5加密 @:param text 需加密字符串 @return 加密后字符串 """ result = hashlib.md5(text) return result.hexdigest() def create_uuid(self): """ 声称随机字符串 :return: """ m = hashlib.md5() m.update(bytes(str(time.time()), encoding='utf-8')) return m.hexdigest() def sha1(self, text): """ sha1 加密 @:param text 需加密字符串 @return 加密后字符串 """ return hashlib.sha1(text).hexdigest() def salt(self, salt_len=6, is_num=False): """ 密码加密字符串 生成一个固定位数的随机字符串,包含0-9a-z @:param salt_len 生成字符串长度 """ if is_num: chrset = '0123456789' else: chrset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ' salt = [] for i in range(salt_len): item = random.choice(chrset) salt.append(item) return ''.join(salt) def out(self, data): """ 输出结果 :param code: 错误信息对象 :param data: 返回数据字典 """ self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(self.json.dumps(data, cls=CJsonEncoder)) def error_out(self, error, data=''): """ 错误输出 :param error: 错误信息对象 :param data: 返回数据字典 :return: """ out = error if data: out['data'] = data self.write(out) def clear_template_cache(self): """ 清除模板缓存 """ self._template_loaders.clear() @tornado.gen.coroutine def get(self): """ 重写父类get方法,接受GET请求 如果执行到此方法,说明请求类型错误 """ self.error_out(self._e('REQUEST_TYPE_ERROR')) @tornado.gen.coroutine def post(self): """ 重写父类post方法,接受POST请求 如果执行到此方法,说明请求类型错误 """ self.error_out(self._e('REQUEST_TYPE_ERROR')) @tornado.gen.coroutine def get_shop_host(self, host): """ 根据二级域名获取店铺ID 规则: 只有当有二级域名,且不为www时执行查找,先从缓存中获取,再从数据库中获取 :param host: :return: """ is_use_domain = 'False' try: is_use_domain = self.properties.get('domain', 'is_use') except Exception, e: print e if host and cmp(is_use_domain, 'True') == 0: hosts = host.split('.') if len(hosts) > 1 and cmp(hosts[0], 'www') != 0 and cmp( hosts[0], 'wxauth') != 0: second_domain = hosts[0] if second_domain: # 获取缓存中的数据 cache_key = self.cache_key_pre.DOAMIN_SHOP_ID + second_domain shop_id = self.redis.get(cache_key) if not shop_id: # 获取数据库中的数据 result = yield self.do_service( 'channel.shop.service', 'query_shop_id', {'domain': second_domain}) if result and result['code'] == 0: shop_id = result['data']['shop_id'] # 设置缓存数据 self.redis.set(cache_key, shop_id, 604800) else: # 获取缓存剩余过期秒数,如果小于3天,则重新设置过期时间 expire_second = self.redis.ttl(cache_key) if int(expire_second) <= 10800: self.redis.expire(cache_key, 604800) if shop_id: self.shop_id = shop_id # 给参数对象添加shop_id # params = self.params() self._params['shop_id'] = shop_id
# -*- coding:utf-8 -*- """ @author: delu @file: __init__.py.py @time: 18/6/20 14:07 """ import importlib from source.properties import Properties from tools.cron_utils import CronUtils from tools.date_utils import DateUtils from constants.error_code import Code cron_utils = CronUtils() properties = Properties('schedule') SCHEDULE_KEY = properties.get('schedule', 'schedule_key') JOB_KEY = properties.get('schedule', 'job_key') RUN_TIME = int(properties.get('schedule', 'run_time')) async def async_add_job(service_path='', method='', params={}, start_time='', cron='', job_id='', group_name='default', repeat_count=0): """ 添加定时任务 :param service_path: 需要执行的service路径
class ServiceBase(object): dicConfig = config.CONF time = time datetime = datetime json = json hashlib = hashlib constants = Constants error_code = Code cache_key_predix = CacheKeyPredix properties = Properties() # redis = AsyncRedis() redis = RedisBase() httputils = HttpUtils date_utils = DateUtils common_utils = CommonUtil string_utils = StringUtils date_encoder = CJsonEncoder rsa_utils = RsaUtils excel_util = excel_util logger = Logs().logger language_code = {} power_tree = [] power_path_list = [] # tornado_redis = TornadoRedis() def md5(self, text): """ md5加密 :param text: :return: """ result = hashlib.md5(text) return result.hexdigest() def import_model(self, model_name): """ 加载数据类 :param model_name: string 数据类名 :return: """ try: model = importlib.import_module('module.' + model_name) return model.Model() except Exception as e: return None def time_to_mktime(self, time_str, format_str): """ 将时间字符串转化成时间戳 :param params: :return: """ return time.mktime(time.strptime(time_str, format_str)) def salt(self, salt_len=6, is_num=False): """ 密码加密字符串 生成一个固定位数的随机字符串,包含0-9a-z @:param salt_len 生成字符串长度 """ if is_num: chrset = '0123456789' else: chrset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ' salt = [] for i in range(salt_len): item = random.choice(chrset) salt.append(item) return ''.join(salt) def create_uuid(self): """ 创建随机字符串 :return: """ m = hashlib.md5() m.update(bytes(str(time.time()) + self.salt(12))) return m.hexdigest() def loads_list(self, list_str): """ 转换字符串成列表 :param list_str: :return: create:wsy 2017/7/31 """ try: data_list = self.json.loads(list_str) except Exception as e: data_list = [] return data_list def loads_dic(self, dic_str): """ 转换字符串成字典 :param dic_str: :return: create:wsy 2017/7/31 """ try: data_dic = self.json.loads(dic_str) except Exception as e: data_dic = {} return data_dic def escape_string(self, data, un=None): """ 特殊字符转义 :param data: string, tuple, list, dict 转义数据 :param un: :return: """ if isinstance(data, str): return tornado.escape.xhtml_escape(data) if not un else tornado.escape.xhtml_unescape(data) elif isinstance(data, tuple) or isinstance(data, list): lisData = [] for item in data: lisData.append( tornado.escape.xhtml_escape(str(item)) if not un else tornado.escape.xhtml_unescape(str(item))) return lisData elif isinstance(data, dict): for key in data: data[key] = tornado.escape.xhtml_escape(str(data[key])) if not un else tornado.escape.xhtml_unescape( str(data[key])) return data def do_service(self, service_path, method, params={}): """ 调用服务 :param service_path: :param method: :param params: :return: """ return serviceManager.do_service(service_path, method, params=params, version=config.CONF['version']) def do_model(self, model_path, method, params={}): """ 调用数据服务 :param model_path: :param method: :param params: :return: """ return modelManager.do_model(model_path, method, params=params, version=config.CONF['version']) def sign_params(self, params, secret_key): """ 验签 :param params: :param secret_key: :return: """ params_keys = [] for (k, v) in params.items(): if k != 'sign': params_keys.append(k) params_string = '' for key in sorted(params_keys): params_string += (key + '=' + params[key] + '&') params_string = self.md5(params_string + secret_key).upper() return params_string == params['sign'].upper() @tornado.gen.coroutine def load_extensions(self, trigger_position, data): """ 加载扩展程序 :param trigger_position: :param data: :return: """ result = yield self.do_service('cfg.extensions.service', 'query', {'trigger_position': trigger_position}) if result and 'code' in result and result['code'] == 0: # 发送消息 for item in result['data']: service_path = item['package_path'] method = item['method'] self.publish_message(service_path, method, data) def publish_message(self, service_path, method, params, task_key=None): """ 发消息到队列中心(redis) :return: """ self.logger.info('发消息 service: %s, method: %s, params: %s', service_path, method, self.json.dumps(params, cls=self.date_encoder)) try: if task_key is None: task_key = self.cache_key_predix.TASK_DATA_LIST result = self.redis.lpush(task_key, self.json.dumps({ 'service_path': service_path, 'method': method, 'params': params }, cls=self.date_encoder)) return result except Exception as e: self.logger.error(e.args) return False def web_event(self, method, event_list, request, data, agent_status=''): """ 页面事件 :param method: :param event_list: :param request: :param data: :param agent_status: 用于判断,是否要记录用户的访问信息,便于后面获取不到用户访问信息时使用,如支付回调 :return: """ t = time.time() cache_key = 'buyer:agent:' + agent_status if not request: request_str = self.redis.get(cache_key) request = self.json.loads(request_str) else: request_str = self.json.dumps(request) if agent_status: # self.redis.set_value(cache_key, request_str) self.redis.set(cache_key, request_str, 60 * 60) message_data = { 'event_list': event_list, 'request': request, 'data': data, 'time': t } self.logger.warning('web_event request: %s, data: %s , time: %s', request_str, self.json.dumps(message_data), t) return self.publish_message('task.statistics.yui.service', method, message_data) def _e(self, error_key): """ :param error_key: :return: """ data = {} for key in self.error_code[error_key]: data[key] = self.error_code[error_key][key] if error_key in self.language_code: data['msg'] = self.language_code[error_key] return data def _gre(self, data): """ tornado.gen.Return :param data: 数据 :return: """ return tornado.gen.Return(self._e(data)) def _grs(self, data={}): """ 成功返回 :param data: :return: """ result = self._e('SUCCESS') result['data'] = data return tornado.gen.Return(result) def _gr(self, data): """ tornado.gen.Return :param data: 数据 :return: """ return tornado.gen.Return(data) def cache_get(self, key): result = self.redis.get(key) if result: expire = self.redis.ttl(key) if expire < self.properties.get('expire', 'CACHE_REFRESH_EXPIRE'): self.redis.expire(key, self.properties.get('expire', 'CACHE_EXPIRE')) try: result = json.loads(result) except Exception as e: self.redis.expire(key, 0) result = False return result else: return False def cache_set(self, key, value): try: value = json.dumps(value, cls=self.date_encoder) self.redis.set(key, value) self.redis.expire(key, self.properties.get('expire', 'CACHE_EXPIRE')) except Exception: return def get_path(self, data): """ 1 遍历用户权限树,如果有child,获得child的path,如果没有,返回power['path'] 2 递归的遍历child获得path,知道所有child为空 3 将所有path加载到power_tree 列表中 :param data: 用户权限树 :return: """ for power in data: if power['child']: self.power_path_list.append(str(power['path'])) self.get_path(power['child']) else: self.power_path_list.append(str(power['path'])) return self.power_path_list
class Service(ServiceBase): """ service """ jala_wechatpay = Properties('jala_wechatpay') base = jala_wechatpay.get('host', 'BASE') notify_url = jala_wechatpay.get('host', 'NOTIFY_URL') refund_url = jala_wechatpay.get('host', 'REFUND_URL') request_url = jala_wechatpay.get('host', 'REQUEST_URL') def __init__(self): """ 对象初始化方法 添加你需要使用的model 格式 项目model文件夹下的文件名或者 包名1.包名2.文件名 (无.py后缀) """ # self.model = self.import_model('') @tornado.gen.coroutine def create_pay(self, params): """ 创建微信支付获取拉起支付数据 :param params: :return: """ check_params = [ 'out_trade_no', 'total_fee', 'spbill_create_ip', 'body', 'openid', 'shop_id' ] if self.common_utils.is_empty(check_params, params): raise self._gre('PARAMS_NOT_EXIST') final_pay = None if not params['self_pay']: pay_result = yield self.do_service('cfg.payment.service', 'query_payments_list', params) if pay_result['code'] != 0: raise self._gr(pay_result) for pay_item in pay_result['data']: if int(pay_item['pay_type']) == self.constants.PAY_TYPE_WECHAT: final_pay = pay_item break if not isinstance(final_pay, dict): raise self._gre('PAY_PAY_PARAMS_NOT_EXIST') else: final_pay = params['self_pay'] cache_key = self.cache_key_predix.ORDER_NOTIFY + params['out_trade_no'] yield self.redis.hmset(cache_key, final_pay, int(params['order_expire_time']) * 60) # 重复支付时从 redis 里面获取 payPackage,1. 判断订单支付状态;2. 获取 payPackage 返回给前端 order_result = yield self.do_service( 'order.service', 'query_sub_order_list', { 'parent_order_id': params['out_trade_no'], 'shop_id': params['shop_id'] }) # 如果查询子订单出错或者子订单状态不为 1 则说明该订单已支付 if order_result['code'] != 0 or order_result['data'][0]['status'] != 1: raise self._gr(order_result) order_pay_cache_key = self.cache_key_predix.ORDER_PAY + params['out_trade_no'] pay_package = yield self.redis.hgetall(order_pay_cache_key) if pay_package: raise self._grs(pay_package) # 组装请求参数 request_params = { 'appid': final_pay['app_id'], 'openid': params['openid'], 'mch_id': final_pay['mch_id'], 'body': params['body'], 'nonce_str': self.create_uuid(), 'out_trade_no': params['out_trade_no'], 'total_fee': params['total_fee'], 'spbill_create_ip': params['spbill_create_ip'], 'notify_url': self.base + self.notify_url, 'trade_type': 'JSAPI', 'time_start': re.sub(r'\s|:|-', '', str(params['order_create_time'])), 'time_expire': re.sub(r'\s|:|-', '', self.date_utils.add_minute(str(params['order_create_time']), minutes=int(params['order_expire_time']))) } self.logger.info('jala_wechatpay_params: %s' % request_params) post_params = self._create_params(request_params, final_pay) request_xml = ['<xml>'] for (k, v) in post_params.items(): request_xml.append('<' + k + '>' + str(v) + '</' + k + '>') request_xml.append('</xml>') self.logger.info(request_xml) res = yield self.httputils.post(self.request_url, params=''.join(request_xml)) self.logger.info(res) try: xml_data = xmltodict.parse(res) except Exception as e: self.logger.exception(e) raise self._gre('PAY_NOTIFY_XML_ERROR') xml_data = xml_data['xml'] if xml_data['return_code'] == 'SUCCESS' and xml_data['result_code'] == 'SUCCESS': result = self._build_h5_response(xml_data, final_pay) # 预支付数据获取成功存进 redis 中 # 拉起第二次支付把预支付参数存进 redis # order_pay_cache_key = self.cache_key_predix.ORDER_PAY + params['out_trade_no'] yield self.redis.hmset(order_pay_cache_key, result, int(params['order_expire_time']) * 61) raise self._grs(result) else: raise self._gre('PAY_PREPAY_ID_ERROR') def _create_params(self, params, final_pay): """ 组装请求参数 :param params: :return: """ params['sign'] = self._create_sign(params, final_pay) return params def _create_sign(self, params, final_pay): """ 生成支付签名 :param params: :return: """ sorted_keys = sorted(params.keys()) params_list = [str(k) + '=' + str(params[k]) for k in sorted_keys if params[k] != ''] params_str = '&'.join(params_list) final_str = params_str + '&key=' + final_pay['mch_api_key'] sign = self.hashlib.md5(final_str.encode('utf-8')) # sign.update(self.private_key.encode('utf-8')) return sign.hexdigest().upper() def _build_h5_response(self, xml_data, pay_params): """ 构建h5调起微信支付返回数据对象 :param xml_data: :param pay_params: :return: """ time_stamp = str(self.time.time()).split('.')[0] pay_sign_list = [ 'appId=' + pay_params['app_id'], 'nonceStr=' + xml_data['nonce_str'], 'package=prepay_id=' + xml_data['prepay_id'], 'signType=MD5', 'timeStamp=' + time_stamp, 'key=' + pay_params['mch_api_key'] ] self.logger.info('&'.join(pay_sign_list)) pay_sign = self.md5('&'.join(pay_sign_list)) result = { 'appId': pay_params['app_id'], 'nonceStr': xml_data['nonce_str'], 'package': 'prepay_id=' + xml_data['prepay_id'], 'signType': 'MD5', 'timeStamp': time_stamp, 'paySign': pay_sign } return result @tornado.gen.coroutine def refund(self, params): """
class Base(Controller): json = json time = time redis = AsyncRedis() error_code = Code properties = Properties() logger = Logs().logger _params = {} @tornado.gen.coroutine def prepare(self): """ 接受请求前置方法 1.解析域名 2.检查IP限制 3.权限检查 :return: """ self._params = self.get_params() def out(self, data): """ 输出结果 :param data: 返回数据字典 """ self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(self.json.dumps(data, cls=CJsonEncoder)) def error_out(self, error, data=''): """ 错误输出 :param error: 错误信息对象 :param data: 返回数据字典 :return: """ out = error if data: out['data'] = data self.write(out) @tornado.gen.coroutine def get(self): """ 重写父类get方法,接受GET请求 如果执行到此方法,说明请求类型错误 """ self.error_out(self._e('REQUEST_TYPE_ERROR')) @tornado.gen.coroutine def post(self): """ 重写父类post方法,接受POST请求 如果执行到此方法,说明请求类型错误 """ self.error_out(self._e('REQUEST_TYPE_ERROR')) def do_service(self, service_path, method, params): """ 调用服务 :param service_path: :param method: :param params: :return: """ version = CommonUtil.get_loader_version(service_path) power_tree = self.settings['power_tree'] return serviceManager.do_service(service_path, method, params=params, version=version, power=power_tree) def _e(self, error_key): """ :param error_key: :return: """ data = {} for key in self.error_code[error_key]: data[key] = self.error_code[error_key][key] return data def _gr(self, data): """ tornado.gen.Return :param data: 数据 :return: """ return tornado.gen.Return(data) def params(self, key=''): """ 获取参数中指定key的数据 :param key: :return: """ if not key: return self._params elif key not in self._params: return '' else: return self._params[key] def get_user_agent(self): """ 获取用户访问数据 :return: """ request = self.request if 'Remote_ip' in request.headers and request.headers['Remote_ip']: ip = request.headers['Remote_ip'] elif 'X-Forward-For' in request.headers and request.headers[ 'X-Forward-For']: ip = request.headers['X-Forward-For'] else: ip = request.remote_ip cookies = '' if request.cookies: for k, v in request.cookies.items(): cookies += k + '=' + v.value + ';' try: user_agent = request.headers['User-Agent'] except Exception as e: user_agent = '' return {'remote_ip': ip, 'user_agent': user_agent, 'cookies': cookies}
# -*- coding:utf-8 -*- """ @package: @file: aio_redis.py @author: yuiitsu @time: 2020-04-03 19:48 """ import ssl import aioredis from source.properties import Properties from tools.logs import Logs properties = Properties() logger = Logs().logger REDIS_HOST = properties.get("redis", "REDIS_HOST") REDIS_PORT = int(properties.get('redis', 'REDIS_PORT')) REDIS_PASS = properties.get('redis', 'REDIS_PASS') REDIS_USE_SSL = properties.get('redis', 'REDIS_USE_SSL') REDIS_MAX_CONNECTION = int(properties.get('redis', 'REDIS_MAX_CONNECTION')) SSLContext = ssl.SSLContext( ) if REDIS_USE_SSL and REDIS_USE_SSL == 'True' else False class AsyncRedis: async def get_conn(self): """ 获取连接 :return: """ redis = await aioredis.create_redis((REDIS_HOST, REDIS_PORT),
class ServiceBase(object): time = time datetime = datetime json = json hashlib = hashlib error_code = Code properties = Properties() redis = AsyncRedis() http_utils = HttpUtils common_utils = CommonUtil logger = Logs().logger lang = LangManager() task = task schedule = schedule def import_model(self, model_name): """ 加载数据类 :param model_name: string 数据类名 :return: """ try: version = self.common_utils.get_loader_version() model = importlib.import_module('src.module.' + version + '.' + model_name) return model.Model() except Exception as e: self.logger.exception(e) return None def do_service(self, service_path, method, params): """ 调用服务 :param service_path: :param method: :param params: :return: """ version = self.common_utils.get_loader_version(service_path) return serviceManager.do_service(service_path, method, params=params, version=version) @tornado.gen.coroutine def load_extensions(self, trigger_position, data): """ 加载扩展程序 :param trigger_position: :param data: :return: """ data['trigger_position'] = trigger_position result = yield self.do_service('v1.cfg.extensions.service', 'query', {'trigger_position': trigger_position}) if result and 'code' in result and result['code'] == 0: # 发送消息 for item in result['data']: service_path = item['package_path'] method = item['method'] yield self.task.add(service_path, method, data) def _e(self, error_key): """ :param error_key: :return: """ data = {} for key in self.error_code[error_key]: data[key] = self.error_code[error_key][key] return data def _gre(self, data): """ tornado.gen.Return :rtype: :param data: 数据 :return: """ return tornado.gen.Return(self._e(data)) def _gree(self, error_key, customer_msg): """ 自定义扩展错误信息 :param error_key: :param customer_msg: 自定义额外错误信息 :return: """ result = self._e(error_key) if customer_msg: result['msg'] += '({})'.format(customer_msg) return tornado.gen.Return(result) def _grs(self, data): """ 成功返回 :param data: :return: """ result = self._e('SUCCESS') result['data'] = data return tornado.gen.Return(result) def _gr(self, data): """ tornado.gen.Return :param data: 数据 :return: """ return tornado.gen.Return(data) @classmethod def params_set(cls, model=None, data=None): """ 数据对象设置 :param model: :param data: :return: """ def decorate(func): @wraps(func) @tornado.gen.coroutine def wrapper(*args, **kwargs): o = args[0] params = args[1] model_data = None if hasattr(o, model): model_obj = getattr(o, model) if hasattr(model_obj, data): model_data = getattr(model_obj, data) new_args = args if model_data: if isinstance(params, dict): model_data.update(params) new_args = (args[0], model_data) result = yield func(*new_args, **kwargs) return result return wrapper return decorate
# -*- coding: utf-8 -*- """ @author: Yuiitsu @file: report @time: 2018/7/13 16:32 """ from email.message import EmailMessage from tornado_smtp.client import TornadoSMTP from source.properties import Properties from tools.date_utils import DateUtils from tools.logs import Logs properties = Properties('task') date_utils = DateUtils() logger = Logs().logger class Report: send_time = 0 smtp_server = properties.get('smtp', 'server') smtp_account = properties.get('smtp', 'account') smtp_pass = properties.get('smtp', 'pass') report_from = properties.get('report', 'from') report_to = properties.get('report', 'to') report_server = properties.get('report', 'server') @classmethod async def report(cls, content, error_track): """
class Base(Controller): json = json error_code = Code redis = RedisBase() user_data = {} auth = None _params = {} properties = Properties() logger = Logs().get_logger() @tornado.gen.coroutine def prepare(self): if self.auth: if self.auth[0] is not None: # 如果控制器需要登录, 则进行登录检查 token = self.get_cookie('token') self.user_data = self.redis.hgetall(token) if not self.user_data: self.error_out(self._e('NOT_LOGIN')) self.finish() def out(self, data): """ 输出结果 :param data: 返回数据字典 """ self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(self.json.dumps(data, cls=CJsonEncoder)) def error_out(self, error, data=''): """ 错误输出 :param error: 错误信息对象 :param data: 返回数据字典 :return: """ out = error if data: out['data'] = data self.write(out) def create_token(self, params): """ 登录成功, 写token :param params: :return: """ token = self.salt() expire_time = int(self.properties.get('expire', 'USER_EXPIRE')) self.redis.hmset(token, params, expire_time) self.set_cookie('token', token, expires=int(time.time()) + expire_time) def salt(self, salt_len=6, is_num=False): """ 密码加密字符串 生成一个固定位数的随机字符串,包含0-9a-z @:param salt_len 生成字符串长度 """ if is_num: chrset = '0123456789' else: chrset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ' salt = [] for i in range(salt_len): item = random.choice(chrset) salt.append(item) return ''.join(salt) @tornado.gen.coroutine def get(self): """ 重写父类get方法,接受GET请求 如果执行到此方法,说明请求类型错误 """ self.error_out(self._e('REQUEST_TYPE_ERROR')) @tornado.gen.coroutine def post(self): """ 重写父类post方法,接受POST请求 如果执行到此方法,说明请求类型错误 """ self.error_out(self._e('REQUEST_TYPE_ERROR')) def _e(self, code): """ 返回错误码 :param code: :return: """ return self.error_code[code] def _gre(self, data): """ tornado.gen.Return :param data: 数据 :return: """ return tornado.gen.Return(self._e(data)) def do_service(self, service_path, method, params={}): """ 调用服务 :param service_path: :param method: :param params: :return: """ return serviceManager.do_service(service_path, method, params=params, version=config.CONF['version']) def params(self, key=''): """ 获取参数中指定key的数据 :param key: :return: """ if not key: return self.get_params() elif key not in self.get_params(): return '' else: return self.get_params(key)