pull/32/merge
Apex Liu 2017-03-03 18:56:51 +08:00
parent 852aba747a
commit 9ad28a298c
9 changed files with 157 additions and 161 deletions

View File

@ -106,6 +106,7 @@ class WebServerCore:
# settings['compiled_template_cache'] = False
# settings['static_hash_cache'] = False
from eom_app.controller import controllers
web_app = tornado.web.Application(controllers, **settings)
@ -117,5 +118,9 @@ class WebServerCore:
log.e('Can not listen on port {}, maybe it been used by another application.\n'.format(cfg.server_port))
return 0
# 启动session超时管理
web_session().start()
tornado.ioloop.IOLoop.instance().start()
web_session().stop()
return 0

View File

@ -1,44 +1,91 @@
# -*- coding: utf-8 -*-
import pickle
# import pickle
import time
import datetime
import threading
from pymemcache.client.base import Client as mem_client
# from pymemcache.client.base import Client as mem_client
from .configs import app_cfg
from eom_common.eomcore.logger import log
cfg = app_cfg()
SESSION_EXPIRE = 3600 # 60*60
SESSION_EXPIRE = 3600 # 60*60 默认超时时间为1小时
# TODO: session接口需要支持超时超时的session应该移除避免内存占用越来越大
# SESSION_EXPIRE = 1800 # 30*60
# SESSION_EXPIRE = 30
class WebSession:
class WebSession(threading.Thread):
"""
:type _mem_client: pymemcache.client.base.Client
"""
def __init__(self):
super().__init__(name='session-manager-thread')
import builtins
if '__web_session__' in builtins.__dict__:
raise RuntimeError('WebSession object exists, you can not create more than one instance.')
# session表session_id为索引每个项为一个字典包括 v(Value), t(Timestamp when add or modify), e(Expire seconds)
self._session_dict = dict()
self._lock = threading.RLock()
self._stop_flag = False
def init(self):
return True
def add(self, s_id, value):
self._session_dict[s_id] = value
def stop(self):
self._stop_flag = True
self.join()
log.v('{} stopped.'.format(self.name))
def set(self, s_id, value):
self._session_dict[s_id] = value
def run(self):
while True:
_now = int(datetime.datetime.utcnow().timestamp())
with self._lock:
_keys = [k for k in self._session_dict]
for k in _keys:
if self._session_dict[k]['e'] == 0:
continue
if _now - self._session_dict[k]['t'] > self._session_dict[k]['e']:
del self._session_dict[k]
# 每隔一分钟检查一次超时的会话
for i in range(60):
if not self._stop_flag:
time.sleep(1)
def set(self, s_id, value, expire=SESSION_EXPIRE):
"""
设置一个会话数据如果expire为负数则立即删除已经存在的名为s_id的会话如果expire为0则此会话数据永不过期expire的单位为秒
@param s_id: string
@param value: string
@param expire: integer
@return: None
"""
if expire < 0:
with self._lock:
if s_id in self._session_dict:
del self._session_dict[s_id]
else:
self._session_dict[s_id] = {'v': value, 't': int(datetime.datetime.utcnow().timestamp()), 'e': expire}
def get(self, s_id, _default=None):
if s_id in self._session_dict:
v = self._session_dict[s_id]
else:
v = _default
return v
with self._lock:
if s_id in self._session_dict:
if self._session_dict[s_id]['e'] == 0:
return self._session_dict[s_id]['v']
else:
if int(datetime.datetime.utcnow().timestamp()) - self._session_dict[s_id]['t'] > self._session_dict[s_id]['e']:
del self._session_dict[s_id]
return _default
else:
self._session_dict[s_id]['t'] = int(datetime.datetime.utcnow().timestamp())
return self._session_dict[s_id]['v']
else:
return _default
def web_session():

View File

@ -1,10 +1,24 @@
# -*- coding: utf-8 -*-
import os
import random
import io
import json
import urllib.parse
import tornado.gen
import tornado.httpclient
from wheezy.captcha.image import background
from wheezy.captcha.image import captcha
from wheezy.captcha.image import curve
from wheezy.captcha.image import noise
from wheezy.captcha.image import offset
from wheezy.captcha.image import rotate
from wheezy.captcha.image import smooth
from wheezy.captcha.image import text
from wheezy.captcha.image import warp
from .configs import app_cfg
cfg = app_cfg()
@ -27,3 +41,38 @@ def async_post_http(url, values):
except:
# return {'code': -2, 'message': 'can not fetch {}'.format(url)}
return None
_chars = 'ACDEFHJKLMNPQRTVWXY34679'
def gen_captcha():
_font_dir = os.path.join(cfg.res_path, 'fonts')
captcha_image_t = captcha(
width=136,
height=36,
drawings=[
background(color='#eeeeee'),
text(fonts=[
os.path.join(_font_dir, '001.ttf')
],
font_sizes=(28, 34, 36, 32),
color='#63a8f5',
squeeze_factor=1.1,
drawings=[
warp(dx_factor=0.05, dy_factor=0.05),
rotate(angle=15),
offset()
]),
curve(color='#af6fff', width=2, number=9),
noise(),
smooth()
])
chars_t = random.sample(_chars, 4)
image = captcha_image_t(chars_t)
out = io.BytesIO()
image.save(out, "jpeg", quality=90)
# web.header('Content-Type','image/jpeg')
return ''.join(chars_t), out.getvalue()

View File

@ -2,19 +2,25 @@
import json
import random
from random import Random
# from random import Random
from eom_app.module import user
from eom_common.eomcore.logger import *
from .base import SwxAppHandler, SwxJsonpHandler, SwxAuthJsonHandler
from .helper.captcha import gen_captcha
from eom_app.app.util import gen_captcha
class LoginHandler(SwxAppHandler):
def get(self):
ref = self.get_argument('ref', '/')
self.render('auth/login.mako', reference=ref, captcha_random=random.random())
user = self.get_current_user()
if user['id'] == 0:
user_name = ''
else:
user_name = user['name']
self.render('auth/login.mako', user_name=user_name, reference=ref, captcha_random=random.random())
class VerifyUser(SwxJsonpHandler):
@ -235,7 +241,6 @@ class ModifyPwd(SwxAuthJsonHandler):
log.e('can not set session.')
self.write_json(-1)
#
# class GetEncData(SwxAuthJsonHandler):
# def post(self):

View File

@ -10,7 +10,7 @@ import mako.template
import tornado.web
from tornado.escape import json_encode
from eom_app.app.session import web_session
from eom_app.app.session import web_session, SESSION_EXPIRE
from eom_app.app.configs import app_cfg
from eom_app.app.const import *
@ -22,8 +22,7 @@ class SwxBaseHandler(tornado.web.RequestHandler):
super().__init__(application, request, **kwargs)
self._s_id = None
self._s_val = dict()
# self.lookup = None
# self._s_val = dict()
def initialize(self):
template_path = self.get_template_path()
@ -46,32 +45,22 @@ class SwxBaseHandler(tornado.web.RequestHandler):
self._s_id = self.get_cookie('_sid')
if self._s_id is None:
self._s_id = 'ywl_{}_{}'.format(int(time.time()), binascii.b2a_hex(os.urandom(8)).decode())
self._s_id = 'tp_{}_{}'.format(int(time.time()), binascii.b2a_hex(os.urandom(8)).decode())
self.set_cookie('_sid', self._s_id)
web_session().add(self._s_id, self._s_val)
else:
# print('sid:', self._s_id)
self._s_val = web_session().get(self._s_id)
if self._s_val is None:
self._s_val = dict()
web_session().add(self._s_id, self._s_val)
def set_session(self, name, value):
self._s_val[name] = value
web_session().set(self._s_id, self._s_val)
def set_session(self, name, value, expire=SESSION_EXPIRE):
k = '{}-{}'.format(self._s_id, name)
web_session().set(k, value, expire)
def get_session(self, name, default=None):
if name in self._s_val:
return self._s_val[name]
else:
return default
def get_session(self, name, _default=None):
k = '{}-{}'.format(self._s_id, name)
return web_session().get(k, _default)
def del_session(self, name):
if name in self._s_val:
del self._s_val[name]
k = '{}-{}'.format(self._s_id, name)
return web_session().set(k, '', -1)
def get_current_user(self):
# return self.get_secure_cookie('user')
user = self.get_session('user')
if user is None:
user = dict()

View File

@ -1,2 +0,0 @@
# -*- coding: utf-8 -*-

View File

@ -1,53 +0,0 @@
# -*- coding: utf-8 -*-
import random
from io import BytesIO, StringIO
from os import path
from eom_app.app.configs import app_cfg
from wheezy.captcha.image import background
from wheezy.captcha.image import captcha
from wheezy.captcha.image import curve
from wheezy.captcha.image import noise
from wheezy.captcha.image import offset
from wheezy.captcha.image import rotate
from wheezy.captcha.image import smooth
from wheezy.captcha.image import text
from wheezy.captcha.image import warp
cfg = app_cfg()
_chars = 'ACDEFHJKLMNPQRTVWXY34679'
def gen_captcha():
_font_dir = path.join(cfg.res_path, 'fonts')
captcha_image_t = captcha(
width=136,
height=36,
drawings=[
background(color='#eeeeee'),
text(fonts=[
path.join(_font_dir, '001.ttf')
],
font_sizes=(28, 34, 36, 32),
color='#63a8f5',
squeeze_factor=1.1,
drawings=[
warp(dx_factor=0.05, dy_factor=0.05),
rotate(angle=15),
offset()
]),
curve(color='#af6fff', width=2, number=9),
noise(),
smooth()
])
chars_t = random.sample(_chars, 4)
image = captcha_image_t(chars_t)
out = BytesIO()
image.save(out, "jpeg", quality=90)
# web.header('Content-Type','image/jpeg')
return ''.join(chars_t), out.getvalue()

View File

@ -15,10 +15,12 @@ from eom_app.app.util import *
from eom_app.module import host
from eom_app.module.common import *
from eom_common.eomcore.logger import *
from .base import SwxAuthHandler, SwxAuthJsonHandler
from .base import SwxAuthHandler, SwxAuthJsonHandler, SwxAdminJsonHandler
cfg = app_cfg()
# 临时认证ID的基数每次使用时均递减
tmp_auth_id_base = -1
class IndexHandler(SwxAuthHandler):
def get(self):
@ -46,7 +48,7 @@ class IndexHandler(SwxAuthHandler):
ts_server['telnet_port'] = cfg.core.telnet.port
# f.write("\"use strict\";\nvar teleport_ip = \"{}\";\n".format(ts_server['ip']))
except Exception as e:
except Exception:
return self.write(-1)
# finally:
# f.close()
@ -773,44 +775,6 @@ class UpdateHostExtendInfo(SwxAuthJsonHandler):
self.write_json(-1)
# @tornado.gen.coroutine
# def post_http(url, values):
# try:
# # log.v('post_http(), url={}\n'.format(url))
#
# # user_agent = 'Mozilla/4.0 (compatible;MSIE 5.5; Windows NT)'
# # values = {
# # 'act': 'login',
# # 'login[email]': 'yzhang@i9i8.com',
# # 'login[password]': '123456'
# # }
# values = json.dumps(values)
# data = urllib.parse.quote(values).encode('utf-8')
# # headers = {'User-Agent': user_agent}
#
# # req = urllib.request.Request(url=url, data=data, headers=headers)
# # response = urllib.request.urlopen(req, timeout=3)
#
# client = tornado.httpclient.AsyncHTTPClient()
# r = yield client.fetch(url, body=data, method='POST')
# print('----------', r.body)
# return r.body
#
#
# # the_page = response.read()
# # info = response.info()
# # _zip = info.get('Content-Encoding')
# # if _zip == 'gzip':
# # the_page = gzip.decompress(the_page)
# # else:
# # pass
# # the_page = the_page.decode()
# # # print(the_page)
# # return the_page
# except:
# return None
class GetSessionId(SwxAuthJsonHandler):
@tornado.gen.coroutine
def post(self, *args, **kwargs):
@ -840,24 +804,11 @@ class GetSessionId(SwxAuthJsonHandler):
url = 'http://{}:{}/rpc'.format(ts_server_rpc_ip, ts_server_rpc_port)
req = {'method': 'request_session', 'param': {'authid': auth_id}}
# values = json.dumps(req)
# data = urllib.parse.quote(values).encode('utf-8')
# client = tornado.httpclient.AsyncHTTPClient()
# r = yield client.fetch(url, body=data, method='POST')
# if r.code == 200:
# # self.write(r.body)
# print('+++++++++', r.body)
_yr = async_post_http(url, req)
return_data = yield _yr
if return_data is None:
return self.write_json(-1)
# return_data = result.decode()
# print('############', return_data)
# return_data = json.loads(result.decode())
if 'code' not in return_data:
return self.write_json(-1)
@ -941,7 +892,7 @@ class AdminGetSessionId(SwxAuthJsonHandler):
return self.write_json(0, data=data)
class AdminFastGetSessionId(SwxAuthJsonHandler):
class AdminFastGetSessionId(SwxAdminJsonHandler):
def post(self, *args, **kwargs):
args = self.get_argument('args', None)
if args is not None:
@ -1001,17 +952,23 @@ class AdminFastGetSessionId(SwxAuthJsonHandler):
values['account'] = 'admin'
# config_list = host.get_config_list()
# ts_server_rpc_ip = '127.0.0.1'
#
# if 'ts_server_rpc_ip' in config_list:
# ts_server_rpc_ip = config_list['ts_server_rpc_ip']
# ts_server_rpc_port = 52080
# if 'ts_server_rpc_port' in config_list:
# ts_server_rpc_port = config_list['ts_server_rpc_port']
ts_server_rpc_ip = cfg.core.rpc.ip
ts_server_rpc_port = cfg.core.rpc.port
# 为统一调用形式这里先将密码或私钥传递给core服务加密然后生成一个临时认证信息供后续request_session时core服务来获取
url = 'http://{}:{}/rpc'.format(ts_server_rpc_ip, ts_server_rpc_port)
req = {'method': 'enc', 'param': {'p': values['uauth']}}
_yr = async_post_http(url, req)
return_data = yield _yr
if return_data is None:
return self.write_json(-1)
if 'code' not in return_data or return_data['code'] != 0:
return self.write_json(-1)
values['uauth'] = return_data['data']['c']
# TODO: 生成一个临时认证信息备用如何保证临时的auth_id唯一
url = 'http://{}:{}/request_session'.format(ts_server_rpc_ip, ts_server_rpc_port)
# values['auth_id'] = auth_id
return_data = post_http(url, values)

View File

@ -53,8 +53,7 @@
<div class="inputbox">
<div class="input-group input-group-lg">
<span class="input-group-addon"><i class="fa fa-user fa-fw"></i></span>
<input id="username_account" type="text" class="form-control" placeholder="账号:邮箱地址或手机号"
data-toggle="popover" data-trigger="manual" data-placement="top">
<input id="username_account" type="text" class="form-control" placeholder="账号:邮箱地址或手机号" data-toggle="popover" data-trigger="manual" data-placement="top" value="${ user_name }">
</div>
</div>