Compare commits

...

10 Commits

Author SHA1 Message Date
yumoqing
6b766496f1 bugfix 2023-11-16 16:20:21 +08:00
yumoqing
578cc3be08 bugfix 2023-11-01 16:34:14 +08:00
yumoqing
5d6610bf0e bugfix 2023-11-01 15:53:20 +08:00
yumoqing
21b2b907fd bugfix 2023-10-27 11:43:23 +08:00
yumoqing
5c0f786a8e bugfix 2023-10-26 11:50:18 +08:00
yumoqing
dab165396d bugfix 2023-10-25 11:48:11 +08:00
yumoqing
335d4daf8d bugfix 2023-10-24 11:57:14 +08:00
yumoqing
bf71b10ab0 bugfix 2023-10-23 17:32:35 +08:00
yumoqing
dcfc9d7ae6 bugfix 2023-10-17 16:07:34 +08:00
yumoqing
12f599ea21 bugfix 2023-10-16 17:20:17 +08:00
4 changed files with 89 additions and 39 deletions

View File

@ -1,13 +1,16 @@
import time import time
import uuid
from aiohttp_auth import auth from aiohttp_auth import auth
from aiohttp_auth.auth.ticket_auth import TktAuthentication from aiohttp_auth.auth.ticket_auth import TktAuthentication
from aiohttp_session.redis_storage import RedisStorage
from os import urandom from os import urandom
from aiohttp import web from aiohttp import web
import aiohttp_session import aiohttp_session
import aioredis import aioredis
import base64 import base64
import binascii
from aiohttp_session import get_session, session_middleware from aiohttp_session import get_session, session_middleware, Session
from aiohttp_session.cookie_storage import EncryptedCookieStorage from aiohttp_session.cookie_storage import EncryptedCookieStorage
from aiohttp_session.redis_storage import RedisStorage from aiohttp_session.redis_storage import RedisStorage
@ -15,6 +18,46 @@ from appPublic.jsonConfig import getConfig
from appPublic.rsawrap import RSA from appPublic.rsawrap import RSA
from appPublic.app_logger import AppLogger from appPublic.app_logger import AppLogger
def get_client_ip(obj, request):
ip = request.headers.get('X-Forwarded-For')
if not ip:
ip = request.remote
request['client_ip'] = ip
return ip
class MyRedisStorage(RedisStorage):
def key_gen(self, request):
key = request.headers.get('client_uuid')
if not key:
key = uuid.uuid4().hex
return key
if isinstance(key, str):
key = key.encode('utf-8')
key = binascii.hexlify(key)
key = key.decode('utf-8')
return key
async def save_session(self, request: web.Request,
response: web.StreamResponse,
session: Session) -> None:
key = session.identity
if key is None:
key = self.key_gen(request)
self.save_cookie(response, key, max_age=session.max_age)
else:
if session.empty:
self.save_cookie(response, "", max_age=session.max_age)
else:
key = str(key)
self.save_cookie(response, key, max_age=session.max_age)
data_str = self._encoder(self._get_session_data(session))
await self._redis.set(
self.cookie_name + "_" + key,
data_str,
ex=session.max_age,
)
class AuthAPI(AppLogger): class AuthAPI(AppLogger):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -37,13 +80,15 @@ class AuthAPI(AppLogger):
async def setupAuth(self,app): async def setupAuth(self,app):
# setup session middleware in aiohttp fashion # setup session middleware in aiohttp fashion
secret = b'iqwertyuiopasdfghjklzxcvbnm12345'
storage = EncryptedCookieStorage(urandom(32)) if self.conf.website.cookie_secret:
secret = self.conf.website.cookie_secret.encode('utf-8')
storage = EncryptedCookieStorage(secret)
if self.conf.website.session_redis: if self.conf.website.session_redis:
url = self.conf.website.session_redis.url url = self.conf.website.session_redis.url
# redis = await aioredis.from_url("redis://127.0.0.1:6379") # redis = await aioredis.from_url("redis://127.0.0.1:6379")
redis = await aioredis.from_url(url) redis = await aioredis.from_url(url)
storage = aiohttp_session.redis_storage.RedisStorage(redis) storage = MyRedisStorage(redis)
aiohttp_session.setup(app, storage) aiohttp_session.setup(app, storage)
# Create an auth ticket mechanism that expires after 1 minute (60 # Create an auth ticket mechanism that expires after 1 minute (60
@ -56,45 +101,52 @@ class AuthAPI(AppLogger):
if self.conf.website.session_reissue_time: if self.conf.website.session_reissue_time:
session_reissue_time = self.conf.website.session_reissue_time session_reissue_time = self.conf.website.session_reissue_time
def _get_ip(self,request):
ip = request.headers.get('X-Forwarded-For')
if not ip:
ip = request.remote
return ip
def _new_ticket(self, request, user_id): def _new_ticket(self, request, user_id):
client_uuid = request.headers.get('client_uuid') client_uuid = request.headers.get('client_uuid')
ip = self._get_ip(request) ip = self._get_ip(request)
if not ip:
ip = request.remote
valid_until = int(time.time()) + self._max_age valid_until = int(time.time()) + self._max_age
print(f'hack: my _new_ticket() called ...remote {ip=}, {client_uuid=}') print(f'hack: my _new_ticket() called ...remote {ip=}, {client_uuid=}')
return self._ticket.new(user_id, valid_until=valid_until, client_ip=ip, user_data=client_uuid) return self._ticket.new(user_id,
valid_until=valid_until,
client_ip=ip,
user_data=client_uuid)
TktAuthentication._get_ip = _get_ip TktAuthentication._get_ip = get_client_ip
TktAuthentication._new_ticket = _new_ticket TktAuthentication._new_ticket = _new_ticket
policy = auth.SessionTktAuthentication(urandom(32), session_max_time, policy = auth.SessionTktAuthentication(secret,
reissue_time=session_reissue_time, session_max_time,
include_ip=True) reissue_time=session_reissue_time,
include_ip=True)
# setup aiohttp_auth.auth middleware in aiohttp fashion # setup aiohttp_auth.auth middleware in aiohttp fashion
# print('policy = ', policy) # print('policy = ', policy)
auth.setup(app, policy) auth.setup(app, policy)
print('add auth middleware ....................')
app.middlewares.append(self.checkAuth) app.middlewares.append(self.checkAuth)
@web.middleware @web.middleware
async def checkAuth(self,request,handler): async def checkAuth(self,request,handler):
print('checkAuth() called ..................') self.info(f'checkAuth() called ...{request.path}')
t1 = time.time()
path = request.path path = request.path
user = await auth.get_auth(request) user = await auth.get_auth(request)
is_ok = await self.checkUserPermission(user, path) is_ok = await self.checkUserPermission(user, path)
t2 = time.time()
ip = get_client_ip(None, request)
if is_ok: if is_ok:
return await handler(request) try:
ret = await handler(request)
t3 = time.time()
self.info(f'timecost=client({ip}) {user} access {path} cost {t3-t1}, ({t2-t1})')
return ret
except Exception as e:
t3 = time.time()
self.info(f'timecost=client({ip}) {user} access {path} cost {t3-t1}, ({t2-t1}), except={e}')
raise e
if user is None: if user is None:
print(f'**{user=}, {path} need login**') self.info(f'timecost=client({ip}) {user} access need login to access {path} ({t2-t1})')
raise web.HTTPUnauthorized raise web.HTTPUnauthorized
print(f'**{user=}, {path} forbidden**') self.info(f'timecost=client({ip}) {user} access {path} forbidden ({t2-t1})')
raise web.HTTPForbidden() raise web.HTTPForbidden()
async def needAuth(self,path): async def needAuth(self,path):

View File

@ -113,3 +113,8 @@ class FileStorage:
# print(f'{name=} file({fpath}) write {siz} bytes') # print(f'{name=} file({fpath}) write {siz} bytes')
self.tfr.newtmpfile(fpath) self.tfr.newtmpfile(fpath)
return fpath return fpath
def file_realpath(path):
fs = FileStorage()
return fs.realPath(path)

View File

@ -4,6 +4,9 @@ import sys
from appPublic.folderUtils import listFile from appPublic.folderUtils import listFile
from appPublic.ExecFile import ExecFile from appPublic.ExecFile import ExecFile
from ahserver.serverenv import ServerEnv from ahserver.serverenv import ServerEnv
import appPublic
import sqlor
import ahserver
def load_plugins(p_dir): def load_plugins(p_dir):
ef = ExecFile() ef = ExecFile()
@ -15,8 +18,11 @@ def load_plugins(p_dir):
ef.set('sys',sys) ef.set('sys',sys)
ef.set('ServerEnv', ServerEnv) ef.set('ServerEnv', ServerEnv)
for m in listFile(pdir, suffixs='.py'): for m in listFile(pdir, suffixs='.py'):
if m.endswith('__init__.py'): if m == '__init__.py':
continue continue
if not m.endswith('.py'):
continue
print(f'{m=}')
module = os.path.basename(m[:-3]) module = os.path.basename(m[:-3])
print('module=', module) print('module=', module)
__import__(module, locals(), globals()) __import__(module, locals(), globals())

View File

@ -47,7 +47,7 @@ from .functionProcessor import FunctionProcessor
from .proxyProcessor import ProxyProcessor from .proxyProcessor import ProxyProcessor
from .serverenv import ServerEnv from .serverenv import ServerEnv
from .url2file import Url2File from .url2file import Url2File
from .filestorage import FileStorage from .filestorage import FileStorage, file_realpath
from .restful import DBCrud from .restful import DBCrud
from .dbadmin import DBAdmin from .dbadmin import DBAdmin
from .filedownload import file_download, path_decode from .filedownload import file_download, path_decode
@ -165,21 +165,6 @@ class ProcessorResource(AppLogger, StaticResource,Url2File):
return ns return ns
async def _handle(self,request:Request) -> StreamResponse: async def _handle(self,request:Request) -> StreamResponse:
name = str(request.url)
t = TimeCost(name)
with t:
try:
x = await self._handle1(request)
except Exception as e:
self.error(f'{name}:error={e}')
print_exc()
x = e
self.info(f'{name}:time cost={t.end_time - t.begin_time}')
if not isinstance(x, StreamResponse):
return HTTPException
return x
async def _handle1(self,request:Request) -> StreamResponse:
clientkeys = { clientkeys = {
"iPhone":"iphone", "iPhone":"iphone",
"iPad":"ipad", "iPad":"ipad",
@ -244,6 +229,7 @@ class ProcessorResource(AppLogger, StaticResource,Url2File):
return await auth.get_auth(request) return await auth.get_auth(request)
self.y_env.i18n = serveri18n self.y_env.i18n = serveri18n
self.y_env.file_realpath = file_realpath
self.y_env.redirect = redirect self.y_env.redirect = redirect
self.y_env.info = self.info self.y_env.info = self.info
self.y_env.error = self.error self.y_env.error = self.error
@ -327,6 +313,7 @@ class ProcessorResource(AppLogger, StaticResource,Url2File):
async def html_handle(self,request,filepath): async def html_handle(self,request,filepath):
async with aiofiles.open(filepath,'r', encoding='utf-8') as f: async with aiofiles.open(filepath,'r', encoding='utf-8') as f:
txt = await f.read() txt = await f.read()
utxt = txt.encode('utf-8')
headers = { headers = {
'Content-Type': 'text/html; utf-8', 'Content-Type': 'text/html; utf-8',
'Accept-Ranges': 'bytes', 'Accept-Ranges': 'bytes',