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 uuid
from aiohttp_auth import auth
from aiohttp_auth.auth.ticket_auth import TktAuthentication
from aiohttp_session.redis_storage import RedisStorage
from os import urandom
from aiohttp import web
import aiohttp_session
import aioredis
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.redis_storage import RedisStorage
@ -15,6 +18,46 @@ from appPublic.jsonConfig import getConfig
from appPublic.rsawrap import RSA
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):
def __init__(self):
super().__init__()
@ -37,13 +80,15 @@ class AuthAPI(AppLogger):
async def setupAuth(self,app):
# setup session middleware in aiohttp fashion
storage = EncryptedCookieStorage(urandom(32))
secret = b'iqwertyuiopasdfghjklzxcvbnm12345'
if self.conf.website.cookie_secret:
secret = self.conf.website.cookie_secret.encode('utf-8')
storage = EncryptedCookieStorage(secret)
if self.conf.website.session_redis:
url = self.conf.website.session_redis.url
# redis = await aioredis.from_url("redis://127.0.0.1:6379")
redis = await aioredis.from_url(url)
storage = aiohttp_session.redis_storage.RedisStorage(redis)
storage = MyRedisStorage(redis)
aiohttp_session.setup(app, storage)
# 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:
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):
client_uuid = request.headers.get('client_uuid')
ip = self._get_ip(request)
if not ip:
ip = request.remote
valid_until = int(time.time()) + self._max_age
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
policy = auth.SessionTktAuthentication(urandom(32), session_max_time,
policy = auth.SessionTktAuthentication(secret,
session_max_time,
reissue_time=session_reissue_time,
include_ip=True)
# setup aiohttp_auth.auth middleware in aiohttp fashion
# print('policy = ', policy)
auth.setup(app, policy)
print('add auth middleware ....................')
app.middlewares.append(self.checkAuth)
@web.middleware
async def checkAuth(self,request,handler):
print('checkAuth() called ..................')
self.info(f'checkAuth() called ...{request.path}')
t1 = time.time()
path = request.path
user = await auth.get_auth(request)
is_ok = await self.checkUserPermission(user, path)
t2 = time.time()
ip = get_client_ip(None, request)
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:
print(f'**{user=}, {path} need login**')
self.info(f'timecost=client({ip}) {user} access need login to access {path} ({t2-t1})')
raise web.HTTPUnauthorized
print(f'**{user=}, {path} forbidden**')
self.info(f'timecost=client({ip}) {user} access {path} forbidden ({t2-t1})')
raise web.HTTPForbidden()
async def needAuth(self,path):

View File

@ -113,3 +113,8 @@ class FileStorage:
# print(f'{name=} file({fpath}) write {siz} bytes')
self.tfr.newtmpfile(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.ExecFile import ExecFile
from ahserver.serverenv import ServerEnv
import appPublic
import sqlor
import ahserver
def load_plugins(p_dir):
ef = ExecFile()
@ -15,8 +18,11 @@ def load_plugins(p_dir):
ef.set('sys',sys)
ef.set('ServerEnv', ServerEnv)
for m in listFile(pdir, suffixs='.py'):
if m.endswith('__init__.py'):
if m == '__init__.py':
continue
if not m.endswith('.py'):
continue
print(f'{m=}')
module = os.path.basename(m[:-3])
print('module=', module)
__import__(module, locals(), globals())

View File

@ -47,7 +47,7 @@ from .functionProcessor import FunctionProcessor
from .proxyProcessor import ProxyProcessor
from .serverenv import ServerEnv
from .url2file import Url2File
from .filestorage import FileStorage
from .filestorage import FileStorage, file_realpath
from .restful import DBCrud
from .dbadmin import DBAdmin
from .filedownload import file_download, path_decode
@ -165,21 +165,6 @@ class ProcessorResource(AppLogger, StaticResource,Url2File):
return ns
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 = {
"iPhone":"iphone",
"iPad":"ipad",
@ -244,6 +229,7 @@ class ProcessorResource(AppLogger, StaticResource,Url2File):
return await auth.get_auth(request)
self.y_env.i18n = serveri18n
self.y_env.file_realpath = file_realpath
self.y_env.redirect = redirect
self.y_env.info = self.info
self.y_env.error = self.error
@ -327,6 +313,7 @@ class ProcessorResource(AppLogger, StaticResource,Url2File):
async def html_handle(self,request,filepath):
async with aiofiles.open(filepath,'r', encoding='utf-8') as f:
txt = await f.read()
utxt = txt.encode('utf-8')
headers = {
'Content-Type': 'text/html; utf-8',
'Accept-Ranges': 'bytes',