def write_log(params): """ 写入日志 :param params: :return: """ try: log_id = params.get('log_id', '') model = ModelBase() logger = Logs().logger path = '' method = '' stack_back = inspect.currentframe() for i in range(len(inspect.stack())): stack_back = stack_back.f_back if stack_back and stack_back.f_locals.get('service_path', ''): path = stack_back.f_locals.get('service_path', '') method = stack_back.f_locals.get('method', '') break if not log_id: insert_params = { 'transfer_method': params['transfer_method'], 'addr': params['addr'], 'path': path, 'method': method, 'params': params['params'], 'result': '', } # 没有log_id则插入 key = 'transfer_method, addr, path, method, params, result' val = '%s, %s, %s, %s, %s, %s' value_tuple = (insert_params['transfer_method'], insert_params['addr'], insert_params['path'], insert_params['method'], insert_params['params'], insert_params['result']) result = model.insert('tbl_thirdpart_connection_logs', { model.sql_constants.KEY: key, model.sql_constants.VAL: val }, tuple(value_tuple)) return result['last_id'] else: # 有log_id则更新 update_params = { 'id': log_id, 'result': params['result'] } fields = [ 'result = %s' ] condition = ' id = %s ' value_tuple = (update_params['result'], update_params['id']) return model.update('tbl_thirdpart_connection_logs', { model.sql_constants.FIELDS: fields, model.sql_constants.CONDITION: condition }, value_tuple) except Exception, e: logger.error('HTTP.POST Exception: %s, path: %s, method: %s, params: %s' % ( e, 'tools.httputils', 'write_log', params)) return None
@file: common_util.py @time: 17/4/24 上午11:31 """ import json import cgi import time import hashlib import random import traceback import re from html.parser import HTMLParser from source.properties import Properties from tools.logs import Logs properties = Properties() logger = Logs().logger class CommonUtil(object): @staticmethod def get_loader_version(path=None): """ 获取调用者的Version """ version = None if path: version = re.findall(r"^v(.+?)\.", path) if version: version = 'v' + version[0] if not version:
class AsyncModelBase(SqlBuilder): async_pools = pools.Pool(dict( host=properties.get('jdbc', 'DB_HOST'), port=int(properties.get('jdbc', 'DB_PORT')), user=properties.get('jdbc', 'DB_USER'), passwd=properties.get('jdbc', 'DB_PASS'), db=properties.get('jdbc', 'DB_BASE'), charset='utf8', autocommit=False, cursorclass=tornado_mysql.cursors.DictCursor), max_idle_connections=5, max_open_connections=100) tx = None sql_builder_orm = None if not sql_builder_orm: sql_builder_orm = SqlBuilderOrm() redis = RedisBase() # redis = AsyncRedis() json = json cache_key_predix = CacheKeyPredix properties = properties date_encoder = CJsonEncoder util = CommonUtil logger = Logs().logger @tornado.gen.coroutine def do_sqls(self, params_list): # 执行多条sql sql = '' tx = None result = None try: tx = yield self.async_pools.begin() for params in params_list: sql_type = params[self.sql_constants.SQL_TYPE] table_name = params[self.sql_constants.TABLE_NAME] dict_data = params[self.sql_constants.DICT_DATA] value_tuple = params[self.sql_constants.VALUE_TUPLE] if sql_type == self.sql_constants.INSERT: # 创建 sql = self.build_insert(table_name, dict_data) elif sql_type == self.sql_constants.BATCH_INSERT: # 批量创建 sql = self.build_batch_insert(table_name, dict_data) elif sql_type == self.sql_constants.UPDATE: # 更新 sql = self.build_update(table_name, dict_data) elif sql_type == self.sql_constants.DELETE: # 删除 sql = self.build_delete(table_name, dict_data) yield tx.execute(sql, value_tuple) if params_list: yield tx.commit() # result = self._gr(self.sql_constants.SUCCESS.copy()) result = self._gr(True) except Exception, e: yield tx.rollback() self.logger.exception(e) print sql raise self._gr(None) raise result
class AsyncModelBase(SqlBuilder): async_pools = pools.Pool( dict(host=properties.get('jdbc', 'DB_HOST'), port=int(properties.get('jdbc', 'DB_PORT')), user=properties.get('jdbc', 'DB_USER'), passwd=properties.get('jdbc', 'DB_PASS'), db=properties.get('jdbc', 'DB_BASE'), charset='utf8', autocommit=False, cursorclass=tornado_mysql.cursors.DictCursor), max_idle_connections=5, max_open_connections=int(properties.get('jdbc', 'MAX_CONNECTIONS')), max_recycle_sec=int(properties.get('jdbc', 'MAX_RECYCLE_SEC'))) tx = None sql_builder_orm = None if not sql_builder_orm: sql_builder_orm = SqlBuilderOrm() # redis = RedisBase() redis = AsyncRedis() json = json cache_key_predix = CacheKeyPredix properties = properties date_encoder = CJsonEncoder util = CommonUtil date_utils = DateUtils logger = Logs().logger constants = constants.Constants @tornado.gen.coroutine def do_sqls(self, params_list): # 执行多条sql sql = '' tx = None result = None try: tx = yield self.async_pools.begin() for params in params_list: sql_type = params[self.sql_constants.SQL_TYPE] table_name = params[self.sql_constants.TABLE_NAME] dict_data = params[self.sql_constants.DICT_DATA] value_tuple = params[self.sql_constants.VALUE_TUPLE] if sql_type == self.sql_constants.INSERT: # 创建 sql = self.build_insert(table_name, dict_data) elif sql_type == self.sql_constants.BATCH_INSERT: # 批量创建 sql = self.build_batch_insert(table_name, dict_data) elif sql_type == self.sql_constants.UPDATE: # 更新 sql = self.build_update(table_name, dict_data) elif sql_type == self.sql_constants.DELETE: # 删除 sql = self.build_delete(table_name, dict_data) yield tx.execute(sql, value_tuple) if params_list: yield tx.commit() # result = self._gr(self.sql_constants.SUCCESS.copy()) result = self._gr(True) except Exception as e: yield tx.rollback() self.logger.exception(e) self.logger.info(sql) raise self._gr(None) raise result @tornado.gen.coroutine def page_find(self, table_name, params, value_tuple): """ 分页查询 :param params: :return: """ # 分页查询 sql = self.build_paginate(table_name, params) sql_count = self.build_get_rows(table_name, params) result = None try: cursor = yield self.async_pools.execute(sql, value_tuple) dict_list = cursor.fetchall() cursor = yield self.async_pools.execute(sql_count, value_tuple) dic_rows = cursor.fetchone() result = { 'list': dict_list, 'row_count': dic_rows[self.sql_constants.ROW_COUNT] if dic_rows else 0 } except Exception as e: self.logger.info(sql) self.logger.info(sql_count) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def get_rows(self, table_name, params, value_tuple): """ 统计数量 :param params: :return: """ sql_count = self.build_get_rows(table_name, params) result = 0 try: cursor = yield self.async_pools.execute(sql_count, value_tuple) dic_rows = cursor.fetchone() result = dic_rows[self.sql_constants.ROW_COUNT] if dic_rows else 0 except Exception as e: self.logger.info(sql_count) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def find(self, table_name, params={}, value_tuple=(), str_type='one'): """ 查询 :param params: :return: """ sql = self.build_select(table_name, params) result = False try: cursor = yield self.async_pools.execute(sql, value_tuple) if str_type == self.sql_constants.LIST: result = cursor.fetchall() else: result = cursor.fetchone() except Exception as e: self.logger.info(sql) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def insert(self, table_name, params, value_tuple, auto_commit=True): """ 创建 :param params: :return: """ sql = self.build_insert(table_name, params) result = None if not self.tx: self.tx = yield self.async_pools.begin() try: if auto_commit: cursor = yield self.tx.execute(sql, value_tuple) yield self.tx.commit() self.tx = None else: cursor = yield self.tx.execute(sql, value_tuple) id = cursor.lastrowid result = self.sql_constants.SUCCESS.copy() result['last_id'] = id result['affected_rows'] = cursor.rowcount except Exception as e: self.tx.rollback() self.logger.info(sql) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def batch_insert(self, table_name, params, value_tuple, auto_commit=True): """ 批量插入 :param table_name: :param params: :param value_tuple: :param auto_commit: :return: """ result = None sql = self.build_batch_insert(table_name, params) if not self.tx: self.tx = yield self.async_pools.begin() try: if auto_commit: cursor = yield self.tx.execute(sql, value_tuple) yield self.tx.commit() self.tx = None else: cursor = yield self.tx.execute(sql, value_tuple) result = self.sql_constants.SUCCESS.copy() result['affected_rows'] = cursor.rowcount except Exception as e: self.logger.info(sql) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def update(self, table_name, params, value_tuple, auto_commit=True): """ 更新 :param params: :return: """ result = None sql = self.build_update(table_name, params) if not self.tx: self.tx = yield self.async_pools.begin() try: if auto_commit: cursor = yield self.tx.execute(sql, value_tuple) yield self.tx.commit() self.tx = None else: cursor = yield self.tx.execute(sql, value_tuple) # result = self.sql_constants.SUCCESS.copy() # result['affected_rows'] = cursor.rowcount result = cursor.rowcount except Exception as e: self.logger.info(sql) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def delete(self, table_name, params, value_tuple, auto_commit=True): """` 删除 :param params: :return: """ sql = self.build_delete(table_name, params) result = None if not self.tx: self.tx = yield self.async_pools.begin() try: if auto_commit: cursor = yield self.tx.execute(sql, value_tuple) yield self.tx.commit() self.tx = None else: cursor = yield self.tx.execute(sql, value_tuple) # result = self.sql_constants.SUCCESS # result['affected_rows'] = cursor.rowcount result = cursor.rowcount except Exception as e: self.logger.info(sql) self.logger.exception(e) raise self._gr(result) def _gr(self, result): """ 异步返回结果 :param result: :return: """ return tornado.gen.Return(result) @tornado.gen.coroutine def find_orm(self, table_name, dict_data, params, str_type='one'): """ orm查询语句 :param table_name: :param dict_data: :param params: :param str_type: :return: """ sql, value_tuple = self.sql_builder_orm.build_select( table_name, dict_data, params) result = False try: cursor = yield self.async_pools.execute(sql, value_tuple) if str_type == self.sql_constants.LIST: result = cursor.fetchall() else: result = cursor.fetchone() except Exception as e: self.logger.info(sql) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def insert_orm(self, table_name, dict_data, params, auto_commit=True): """ 创建 :param params: :return: """ sql, value_tuple = self.sql_builder_orm.build_insert( table_name, dict_data, params) result = None if not self.tx: self.tx = yield self.async_pools.begin() try: if auto_commit: cursor = yield self.tx.execute(sql, value_tuple) yield self.tx.commit() self.tx = None else: cursor = yield self.tx.execute(sql, value_tuple) result = {'last_id': cursor.lastrowid} except Exception as e: self.tx.rollback() self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def update_orm(self, table_name, dict_data, params, auto_commit=True): """ 更新 :param params: :return: """ result = None sql, value_tuple = self.sql_builder_orm.build_update( table_name, dict_data, params) if not self.tx: self.tx = yield self.async_pools.begin() try: if auto_commit: cursor = yield self.tx.execute(sql, value_tuple) yield self.tx.commit() self.tx = None else: cursor = yield self.tx.execute(sql, value_tuple) result = self.sql_constants.SUCCESS result['affected_rows'] = cursor.rowcount except Exception as e: self.logger.info(sql) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def delete_orm(self, table_name, dict_data, params, auto_commit=True): """` 删除 :param params: :return: """ sql, value_tuple = self.sql_builder_orm.build_delete( table_name, dict_data, params) result = None if not self.tx: self.tx = yield self.async_pools.begin() try: if auto_commit: cursor = yield self.tx.execute(sql, value_tuple) yield self.tx.commit() self.tx = None else: cursor = yield self.tx.execute(sql, value_tuple) # result = self.sql_constants.SUCCESS # result['affected_rows'] = cursor.rowcount result = cursor.rowcount except Exception as e: self.logger.info(sql) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def page_find_orm(self, table_name, dict_data, params): """ 分页查询 :param params: :return: """ # 分页查询 sql, value_tuple = self.sql_builder_orm.build_paginate( table_name, dict_data, params) sql_count, count_value_tuple = self.sql_builder_orm.build_count( table_name, dict_data, params) result = None try: cursor = yield self.async_pools.execute(sql, value_tuple) dict_list = cursor.fetchall() cursor = yield self.async_pools.execute(sql_count, count_value_tuple) dic_rows = cursor.fetchone() result = { 'list': dict_list, 'row_count': dic_rows[self.sql_constants.ROW_COUNT] if dic_rows else 0 } except Exception as e: self.logger.info(sql) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def get_rows_orm(self, table_name, dict_data, params): """ 统计数量 :param params: :return: """ sql_count, value_tuple = self.sql_builder_orm.build_count( table_name, dict_data, params) result = 0 try: cursor = yield self.async_pools.execute(sql_count, value_tuple) dic_rows = cursor.fetchone() result = dic_rows[self.sql_constants.ROW_COUNT] if dic_rows else 0 except Exception as e: self.logger.info(sql_count) self.logger.exception(e) raise self._gr(result) @tornado.gen.coroutine def do_sqls_orm(self, params_list): # 执行多条sql sql = '' tx = None result = None try: tx = yield self.async_pools.begin() for params in params_list: sql_type = params[self.sql_constants.SQL_TYPE] table_name = params[self.sql_constants.TABLE_NAME] dict_data = params[self.sql_constants.DICT_DATA] value_params = params[self.sql_constants.VALUE_PARAMS] if sql_type == self.sql_constants.INSERT: # 创建 sql, value_tuple = self.sql_builder_orm.build_insert( table_name, dict_data, value_params) elif sql_type == self.sql_constants.UPDATE: # 更新 sql, value_tuple = self.sql_builder_orm.build_update( table_name, dict_data, value_params) elif sql_type == self.sql_constants.DELETE: # 删除 sql, value_tuple = self.sql_builder_orm.build_delete( table_name, dict_data, value_params) yield tx.execute(sql, value_tuple) if params_list: yield tx.commit() result = self._gr(self.sql_constants.SUCCESS) except Exception as e: yield tx.rollback() self.logger.info(sql) self.logger.exception(e) raise self._gr(None) raise result @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, int(self.properties.get('expire', 'CACHE_EXPIRE'))) try: result = json.loads(result) except Exception as e: yield self.redis.expire(key, 0) result = False self.logger.exception(e) raise self._gr(result) else: raise self._gr(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, int(self.properties.get('expire', 'CACHE_EXPIRE'))) raise self._gr(True) except Exception as e: if isinstance(e, tornado.gen.Return): raise self._gr(e) self.logger.exception(e) raise self._gr(False) @tornado.gen.coroutine def cache_mget(self, keys): """ 批量获取缓存 :param keys: :return: """ values = yield self.redis.mget(keys) result = list() error_keys = list() for index in range(len(keys)): if values[index]: try: # 更新缓存过期时间 result.append(json.loads(values[index])) expire = yield self.redis.ttl(keys[index]) if expire < int( self.properties.get('expire', 'CACHE_REFRESH_EXPIRE')): yield self.redis.expire( keys[index], int(self.properties.get('expire', 'CACHE_EXPIRE'))) except Exception as e: self.logger.exception(e) error_keys.append(keys[index]) yield self.redis.expire(keys[index], 0) else: error_keys.append(keys[index]) raise self._gr({'data': result, 'error': error_keys}) @tornado.gen.coroutine def cache_del(self, *key): """ 删除缓存 author: yuiitsu date: 2017-09-27 :param key: :return: """ if key: result = yield self.redis.delete(*key) raise self._gr(result)
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
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 logger = Logs().get_logger() def update_task(last_id): """ 更新任务完成状态 :param last_id: :return: """ model = ModelBase() fields = ['is_complete = 1'] condition = ' id = %s ' value_tuple = (last_id, ) result = model.update( 'tbl_task_job_logs', { model.sql_constants.FIELDS: fields,
import importlib 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 需要执行的任务列表
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 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
class RedisBase(object): pool = redis.ConnectionPool(host=properties.get("redis", "REDIS_HOST"), port=properties.get("redis", "REDIS_PORT"), password=properties.get("redis", "REDIS_PASS"), decode_responses=True, max_connections=1000) logger = Logs().logger def get_conn(self): return redis.StrictRedis(connection_pool=self.pool) def set_value(self, key, value): try: resource = self.get_conn() resource.set(key, value) except Exception as e: self.logger.exception(e) def set(self, key, value, second=0): try: resource = self.get_conn() if second > 0: resource.setex(key, second, value) else: resource.set(key, value) except Exception as e: self.logger.exception(e) def get(self, key): try: resource = self.get_conn() return resource.get(key) except Exception as e: self.logger.exception(e) def delete(self, *key): result = None try: resource = self.get_conn() result = resource.delete(*key) except Exception as e: self.logger.exception(e) return result def hmset(self, key, value, second=0): try: resource = self.get_conn() with resource.pipeline() as pipe: pipe.hmset(key, value) if second > 0: pipe.expire(key, int(second)) pipe.execute() except Exception as e: self.logger.exception(e) def hgetall(self, key): try: resource = self.get_conn() return resource.hgetall(key) except Exception as e: self.logger.exception(e) def mget(self, key): try: resource = self.get_conn() return resource.mget(key) except Exception as e: self.logger.exception(e) def ttl(self, key): try: resource = self.get_conn() return resource.ttl(key) except Exception as e: self.logger.exception(e) def expire(self, key, second=0): try: resource = self.get_conn() return resource.expire(key, int(second)) except Exception as e: self.logger.exception(e) def incr(self, key, amount=1): try: resource = self.get_conn() return resource.incr(key, amount) except Exception as e: self.logger.exception(e) def decr(self, key, amount=1): try: resource = self.get_conn() return resource.decr(key, amount) except Exception as e: self.logger.exception(e) def sadd(self, key, value): try: resource = self.get_conn() return resource.sadd(key, value) except Exception as e: self.logger.exception(e) def srem(self, key, value): try: resource = self.get_conn() return resource.srem(key, value) except Exception as e: self.logger.exception(e) def smembers(self, key): try: resource = self.get_conn() return resource.smembers(key) except Exception as e: self.logger.exception(e) def spop(self, key): try: resource = self.get_conn() return resource.spop(key) except Exception as e: self.logger.exception(e) def srem(self, key, value): try: resource = self.get_conn() return resource.srem(key, value) except Exception as e: self.logger.exception(e) def lpush(self, key, value): try: resource = self.get_conn() return resource.lpush(key, value) except Exception as e: self.logger.exception(e) def rpush(self, key, value): try: resource = self.get_conn() return resource.rpush(key, value) except Exception as e: self.logger.exception(e) def rpop(self, key): try: resource = self.get_conn() return resource.rpop(key) except Exception as e: self.logger.exception(e) raise e def llen(self, key): try: resource = self.get_conn() return resource.llen(key) except Exception as e: self.logger.exception(e) def lrange(self, key, start, end): try: resource = self.get_conn() return resource.lrange(key, start, end) except Exception as e: self.logger.exception(e) def hincrby(self, key, field, increment=1): try: resource = self.get_conn() return resource.hincrby(key, field, increment) except Exception as e: self.logger.exception(e) def hget(self, key, field): try: resource = self.get_conn() return resource.hget(key, field) except Exception as e: self.logger.exception(e) def hset(self, key, field, value): try: resource = self.get_conn() return resource.hset(key, field, value) except Exception as e: self.logger.exception(e) def hdel(self, key, field): try: resource = self.get_conn() return resource.hdel(key, field) except Exception as e: self.logger.exception(e) def scard(self, key): try: resource = self.get_conn() return resource.scard(key) except Exception as e: self.logger.exception(e)
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}
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
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)
class Controller(tornado.web.RequestHandler): """ 基类 """ controllerKey = '' # controller对应的key user_type = None config = None view_data = {} # 模板输出数据 model = None _GET = False _POST = False view_path = '' escape = tornado.escape version = '' importlib = importlib logger = Logs().logger def initialize(self): """ 初始化 :return: """ # self.view_path = self.config['VIEW_PATH'] def on_finish(self): """ """ # self.model.__del__() pass @tornado.gen.coroutine def display(self, view_name, view_path=''): """ 输出模板 调用模板输出,使用当前类名为模板目录 @params viewName string 调用模板名称 @params data dict 输出数据 """ view_path = view_path if view_path else self.view_path if not self.config['debug']: try: self.render("%s/%s/%s.html" % (view_path, self.__class__.__name__, view_name), controller=self.__class__.__name__, **self.view_data) except Exception as e: self.logger.exception(e) self.redirect('/700') return else: self.render("%s/%s/%s.html" % (view_path, self.__class__.__name__, view_name), controller=self.__class__.__name__, **self.view_data) def get_params(self, key=""): """ 获取请求参数 如果只有一个值,将其转为字符串,如果是list,保留list类型 @:param key 参数名称 @:param data_type 返回数据类型,默认 """ if not key: result = {} data = self.request.arguments for (k, v) in data.items(): if len(v) > 1: value_strip = [] for item in v: value_strip.append(item.strip()) result[k] = value_strip else: result[k] = v[0].strip().decode('utf-8') return result else: try: value = self.request.arguments[key] if len(value) > 1: value_strip = [] for item in value: value_strip.append(item.strip()) return value_strip else: return value[0].strip().decode('utf-8') except Exception as e: return '' def import_model(self, model_name): """ 加载类 @:param model_name 类名 @:param model_dir 目录 """ try: model = importlib.import_module(self.version + '.model.' + model_name) return model.Model(self.model) except Exception as e: self.logger.exception(e) return None def import_service(self, service_name): """ 加载服务类 @params service_name 服务类名 @params service_dir 服务类所在目录 """ try: service = importlib.import_module(self.version + '.service.' + service_name) return service.Service() except Exception as e: self.logger.exception(e) return None def write_error(self, status_code, **kwargs): """ 复写方法 :param status_code: :param kwargs: :return: """ self.set_header("Content-Type", "application/json; charset=UTF-8") self.write({ 'code': -status_code, 'msg': '服务错误,请联系管理员', 'traceback': kwargs['traceback_error'] }) self.finish() def send_error(self, status_code=500, **kwargs): """ 复写方法 :param status_code: :param kwargs: :return: """ if self._headers_written: # gen_log.error("Cannot send error response after headers written") self.logger.info( 'Cannot send error response after headers written') if not self._finished: self.finish() return self.clear() if 'exc_info' in kwargs: kwargs['traceback_error'] = traceback.format_exc() self.set_status(status_code) try: self.write_error(status_code, **kwargs) except Exception as e: self.logger.exception(e) if not self._finished: self.finish()