reyserver 1.1.58__py3-none-any.whl → 1.1.60__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of reyserver might be problematic. Click here for more details.

reyserver/radmin.py CHANGED
@@ -12,7 +12,9 @@
12
12
  from typing import Any, Type
13
13
  from collections.abc import Sequence
14
14
  from sqlalchemy.ext.asyncio import async_sessionmaker
15
+ from fastapi import Request
15
16
  from sqladmin import Admin, ModelView
17
+ from sqladmin.authentication import AuthenticationBackend
16
18
  from reydb import DatabaseEngineAsync, rorm
17
19
  from reykit.rbase import Singleton
18
20
 
@@ -23,11 +25,12 @@ from . import rserver
23
25
  __all__ = (
24
26
  'ServerAdminModel',
25
27
  'ServerAdminModelView',
26
- 'ServerAdminModelViewStats'
28
+ 'ServerAdminModelViewStats',
29
+ 'ServerAdmin'
27
30
  )
28
31
 
29
32
 
30
- class ServerAdminModel(ModelView):
33
+ class ServerAdminModel(ServerBase, ModelView):
31
34
  """
32
35
  Server admin model type.
33
36
  """
@@ -50,6 +53,40 @@ class ServerAdminModelViewStats(ServerAdminModelView):
50
53
  column_list = ['item', 'value', 'comment']
51
54
 
52
55
 
56
+ # class ServerAdminAuthentication(ServerAdmin, AuthenticationBackend):
57
+ # """
58
+ # Server admin authentication type.
59
+ # """
60
+
61
+
62
+ # async def authenticate(self, request: Request) -> bool:
63
+ # """
64
+ # Authenticate request.
65
+
66
+ # Parameters
67
+ # ----------
68
+ # request : Request.
69
+ # """
70
+
71
+ # #
72
+ # ...
73
+ # request.session['token']
74
+ # ...
75
+
76
+
77
+ # async def login(self, request: Request) -> bool:
78
+ # form = await request.form()
79
+ # form['username']
80
+ # form['password']
81
+ # ...
82
+ # request.session['token'] = ...
83
+ # ...
84
+
85
+
86
+ # async def logout(self, request: Request) -> None:
87
+ # request.session.clear()
88
+
89
+
53
90
  class ServerAdmin(ServerBase, Singleton):
54
91
  """
55
92
  Server admin type, singleton mode.
@@ -73,7 +110,13 @@ class ServerAdmin(ServerBase, Singleton):
73
110
  'Admin API model bind database engine dictionary.'
74
111
  Session = async_sessionmaker()
75
112
  Session.configure(binds=self.api_admin_binds)
76
- self.admin = Admin(self.server.app, session_maker=Session)
113
+ auth = self.__create_auth()
114
+ self.admin = Admin(
115
+ self.server.app,
116
+ session_maker=Session,
117
+ authentication_backend=auth
118
+ )
119
+
77
120
 
78
121
 
79
122
  def add_model(
reyserver/rauth.py CHANGED
@@ -9,14 +9,18 @@
9
9
  """
10
10
 
11
11
 
12
- from typing import Any, Literal
12
+ from typing import Any, TypedDict, NotRequired, Literal
13
13
  from datetime import datetime as Datetime
14
+ from re import PatternError
14
15
  from fastapi import APIRouter, Request
16
+ from fastapi.params import Depends
17
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
15
18
  from reydb import rorm, DatabaseEngine, DatabaseEngineAsync
16
- from reykit.rdata import encode_jwt, is_hash_bcrypt
19
+ from reykit.rdata import encode_jwt, decode_jwt, is_hash_bcrypt
20
+ from reykit.rre import search_batch
17
21
  from reykit.rtime import now
18
22
 
19
- from .rbase import ServerConfig, Bind, exit_api
23
+ from .rbase import Bind, exit_api
20
24
 
21
25
 
22
26
  __all__ = (
@@ -30,6 +34,34 @@ __all__ = (
30
34
  )
31
35
 
32
36
 
37
+ UserInfo = TypedDict(
38
+ 'UserInfo',
39
+ {
40
+ 'create_time': float,
41
+ 'udpate_time': float,
42
+ 'user_id': int,
43
+ 'user_name': str,
44
+ 'role_names': list[str],
45
+ 'perm_names': list[str],
46
+ 'perm_apis': list[str],
47
+ 'email': str | None,
48
+ 'phone': str | None,
49
+ 'avatar': int | None,
50
+ 'password': NotRequired[str]
51
+ }
52
+ )
53
+ Token = TypedDict(
54
+ 'Token',
55
+ {
56
+ 'sub': int,
57
+ 'iat': int,
58
+ 'nbf': int,
59
+ 'exp': int,
60
+ 'user': UserInfo
61
+ }
62
+ )
63
+
64
+
33
65
  class DatabaseORMTableUser(rorm.Table):
34
66
  """
35
67
  Database `user` table ORM model.
@@ -202,40 +234,50 @@ def build_auth_db(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
202
234
  auth_router = APIRouter()
203
235
 
204
236
 
205
- @auth_router.post('/sessions')
206
- async def create_sessions(
207
- account: str = Bind.i.body,
208
- password: str = Bind.i.body,
209
- account_type: Literal['name', 'email', 'phone'] = Bind.Body('name'),
210
- conn: Bind.Conn = Bind.conn.auth
211
- ) -> dict:
237
+ async def get_user_info(
238
+ conn: Bind.Conn,
239
+ account: str,
240
+ account_type: Literal['name', 'email', 'phone'],
241
+ filter_invalid: bool = True
242
+ ) -> UserInfo | None:
212
243
  """
213
- Create session.
244
+ Get user information.
214
245
 
215
246
  Parameters
216
247
  ----------
217
- account : User account, name or email or phone.
218
- password : User password.
248
+ conn: Asyncronous database connection.
249
+ account : User account.
219
250
  account_type : User account type.
251
+ - `Literal['name']`: User name.
252
+ - `Literal['email']`: User Email.
253
+ - `Literal['phone']`: User phone mumber.
254
+ filter_invalid : Whether filter invalid user.
220
255
 
221
256
  Returns
222
257
  -------
223
- JSON with `token`.
258
+ User information or null.
224
259
  """
225
260
 
226
- # Parameter.
227
- key = ServerConfig.server.api_auth_key
228
- sess_seconds = ServerConfig.server.api_auth_sess_seconds
229
-
230
- # Check.
261
+ # Parameters.
262
+ if filter_invalid:
263
+ sql_where = (
264
+ ' WHERE (\n'
265
+ f' `{account_type}` = :account\n'
266
+ ' AND `is_valid` = 1\n'
267
+ ' )\n'
268
+ )
269
+ else:
270
+ sql_where = ' WHERE `{account_type}` = :account\n'
271
+
272
+ # Get.
231
273
  sql = (
232
274
  'SELECT ANY_VALUE(`create_time`) AS `create_time`,\n'
275
+ ' ANY_VALUE(`phone`) AS `phone`,\n'
233
276
  ' ANY_VALUE(`update_time`) AS `update_time`,\n'
234
277
  ' ANY_VALUE(`user`.`user_id`) AS `user_id`,\n'
235
278
  ' ANY_VALUE(`user`.`name`) AS `user_name`,\n'
236
279
  ' ANY_VALUE(`password`) AS `password`,\n'
237
280
  ' ANY_VALUE(`email`) AS `email`,\n'
238
- ' ANY_VALUE(`phone`) AS `phone`,\n'
239
281
  ' ANY_VALUE(`avatar`) AS `avatar`,\n'
240
282
  " GROUP_CONCAT(DISTINCT `role`.`name` SEPARATOR ';') AS `role_names`,\n"
241
283
  " GROUP_CONCAT(DISTINCT `perm`.`name` SEPARATOR ';') AS `perm_names`,\n"
@@ -243,8 +285,7 @@ async def create_sessions(
243
285
  'FROM (\n'
244
286
  ' SELECT `create_time`, `update_time`, `user_id`, `password`, `name`, `email`, `phone`, `avatar`\n'
245
287
  ' FROM `test`.`user`\n'
246
- f' WHERE `{account_type}` = :account\n'
247
- ' LIMIT 1\n'
288
+ f'{sql_where}'
248
289
  ') as `user`\n'
249
290
  'LEFT JOIN (\n'
250
291
  ' SELECT `user_id`, `role_id`\n'
@@ -262,7 +303,7 @@ async def create_sessions(
262
303
  ') as `role_perm`\n'
263
304
  'ON `role_perm`.`role_id` = `role`.`role_id`\n'
264
305
  'LEFT JOIN (\n'
265
- " SELECT `perm_id`, `name`, CONCAT(`method`, ':', `path`) as `api`\n"
306
+ " SELECT `perm_id`, `name`, `api`\n"
266
307
  ' FROM `test`.`perm`\n'
267
308
  ') AS `perm`\n'
268
309
  'ON `role_perm`.`perm_id` = `perm`.`perm_id`\n'
@@ -273,34 +314,137 @@ async def create_sessions(
273
314
  account=account
274
315
  )
275
316
 
276
- # Check.
317
+ # Extract.
277
318
  if result.empty:
319
+ info = None
320
+ else:
321
+ row: dict[str, Datetime | Any] = result.to_row()
322
+ info: UserInfo = {
323
+ 'create_time': row['create_time'].timestamp(),
324
+ 'udpate_time': row['update_time'].timestamp(),
325
+ 'user_id': row['user_id'],
326
+ 'user_name': row['user_name'],
327
+ 'role_names': row['role_names'].split(';'),
328
+ 'perm_names': row['perm_names'].split(';'),
329
+ 'perm_apis': row['perm_apis'].split(';'),
330
+ 'email': row['email'],
331
+ 'phone': row['phone'],
332
+ 'avatar': row['avatar'],
333
+ 'password': row['password']
334
+ }
335
+
336
+ return info
337
+
338
+
339
+ @auth_router.post('/sessions')
340
+ async def create_sessions(
341
+ account: str = Bind.i.body,
342
+ password: str = Bind.i.body,
343
+ account_type: Literal['name', 'email', 'phone'] = Bind.Body('name'),
344
+ conn: Bind.Conn = Bind.conn.auth,
345
+ server: Bind.Server = Bind.server
346
+ ) -> dict:
347
+ """
348
+ Create session.
349
+
350
+ Parameters
351
+ ----------
352
+ account : User account.
353
+ password : User password.
354
+ account_type : User account type.
355
+ - `Literal['name']`: User name.
356
+ - `Literal['email']`: User Email.
357
+ - `Literal['phone']`: User phone mumber.
358
+
359
+ Returns
360
+ -------
361
+ JSON with `token`.
362
+ """
363
+
364
+ # Parameter.
365
+ key = server.api_auth_key
366
+ sess_seconds = server.api_auth_sess_seconds
367
+
368
+ # User information.
369
+ info = await get_user_info(conn, account, account_type)
370
+
371
+ # Check.
372
+ if info is None:
278
373
  exit_api(401)
279
- json: dict[str, Datetime | Any] = result.to_row()
280
- if not is_hash_bcrypt(password, json['password']):
374
+ password_hash = info.pop('password')
375
+ if not is_hash_bcrypt(password, password_hash):
281
376
  exit_api(401)
282
377
 
283
378
  # JWT.
284
379
  now_timestamp_s = now('timestamp_s')
285
- json['sub'] = json.pop('user_id')
286
- json['iat'] = now_timestamp_s
287
- json['nbf'] = now_timestamp_s
288
- json['exp'] = now_timestamp_s + sess_seconds
289
- json['role_names'] = json['role_names'].split(';')
290
- json['perm_names'] = json['perm_names'].split(';')
291
- perm_apis: list[str] = json['perm_apis'].split(';')
292
- perm_api_dict = {}
293
- for perm_api in perm_apis:
294
- method, path = perm_api.split(':', 1)
295
- paths: list = perm_api_dict.setdefault(method, [])
296
- paths.append(path)
297
- json['perm_apis'] = perm_api_dict
298
- json['create_time'] = json['create_time'].timestamp()
299
- json['update_time'] = json['update_time'].timestamp()
300
- token = encode_jwt(json, key)
301
- data = {'token': token}
302
-
303
- return data
304
-
305
-
306
- def has_auth(request: Request) -> bool: ...
380
+ user_id = info.pop('user_id')
381
+ data: Token = {
382
+ 'sub': str(user_id),
383
+ 'iat': now_timestamp_s,
384
+ 'nbf': now_timestamp_s,
385
+ 'exp': now_timestamp_s + sess_seconds,
386
+ 'user': info
387
+ }
388
+ token = encode_jwt(data, key)
389
+ response = {'token': token}
390
+
391
+ return response
392
+
393
+
394
+ bearer = HTTPBearer(
395
+ scheme_name='RBACBearer',
396
+ description='Global authentication of based on RBAC model and Bearer framework.',
397
+ bearerFormat='JWT standard.',
398
+ auto_error=False
399
+ )
400
+
401
+
402
+ async def depend_auth(
403
+ request: Request,
404
+ server: Bind.Server = Bind.server,
405
+ auth: HTTPAuthorizationCredentials | None = Depends(bearer)
406
+ ) -> None:
407
+ """
408
+ Dependencie function of authentication.
409
+
410
+ Parameters
411
+ ----------
412
+ request : Request.
413
+ server : Server.
414
+ auth : Authentication.
415
+ """
416
+
417
+ # Check.
418
+ print(11111111111111111)
419
+ api_path = f'{request.method} {request.url.path}'
420
+ if (
421
+ not server.is_started_auth
422
+ or api_path == 'POST /sessions'
423
+ ):
424
+ return
425
+ if auth is None:
426
+ exit_api(401)
427
+
428
+ # Parameter.
429
+ key = server.api_auth_key
430
+ token = auth.credentials
431
+
432
+ # Decode.
433
+ json = decode_jwt(token, key)
434
+ if json is None:
435
+ exit_api(401)
436
+ json: Token
437
+ request.state.user = json['user']
438
+
439
+ # Check.
440
+ perm_apis = json['user']['perm_apis']
441
+ perm_apis = [
442
+ f'^{pattern}$'
443
+ for pattern in perm_apis
444
+ ]
445
+ try:
446
+ result = search_batch(api_path, *perm_apis)
447
+ except PatternError:
448
+ exit_api(403)
449
+ if result is None:
450
+ exit_api(403)
reyserver/rbase.py CHANGED
@@ -9,8 +9,9 @@
9
9
  """
10
10
 
11
11
 
12
- from typing import NoReturn, overload
12
+ from typing import Type, NoReturn, overload
13
13
  from http import HTTPStatus
14
+ from fastapi import FastAPI
14
15
  from fastapi import HTTPException, Request, UploadFile as File
15
16
  from fastapi.params import (
16
17
  Depends,
@@ -24,14 +25,13 @@ from fastapi.params import (
24
25
  )
25
26
  from reydb.rconn import DatabaseConnectionAsync
26
27
  from reydb.rorm import DatabaseORMModel, DatabaseORMSessionAsync
27
- from reykit.rbase import Base, Exit, StaticMeta, ConfigMeta, Singleton, throw
28
+ from reykit.rbase import Base, Exit, StaticMeta, Singleton, throw
28
29
 
29
30
  from . import rserver
30
31
 
31
32
 
32
33
  __all__ = (
33
34
  'ServerBase',
34
- 'ServerConfig',
35
35
  'ServerExit',
36
36
  'ServerExitAPI',
37
37
  'exit_api',
@@ -50,15 +50,6 @@ class ServerBase(Base):
50
50
  """
51
51
 
52
52
 
53
- class ServerConfig(ServerBase, metaclass=ConfigMeta):
54
- """
55
- Config type.
56
- """
57
-
58
- server: 'rserver.Server'
59
- 'Server instance.'
60
-
61
-
62
53
  class ServerExit(ServerBase, Exit):
63
54
  """
64
55
  Server exit type.
@@ -116,13 +107,13 @@ class ServerBindInstanceDatabaseSuper(ServerBase):
116
107
  """
117
108
 
118
109
 
119
- async def depend_func():
110
+ async def depend_func(server: Bind.Server = Bind.server):
120
111
  """
121
112
  Dependencie function of asynchronous database.
122
113
  """
123
114
 
124
115
  # Parameter.
125
- engine = ServerConfig.server.db[name]
116
+ engine = server.db[name]
126
117
 
127
118
  # Context.
128
119
  match self:
@@ -320,6 +311,26 @@ class ServerBindInstance(ServerBase, Singleton):
320
311
  return forms
321
312
 
322
313
 
314
+ async def depend_server(request: Request) -> 'rserver.Server':
315
+ """
316
+ Dependencie function of now Server instance.
317
+
318
+ Parameters
319
+ ----------
320
+ request : Request.
321
+
322
+ Returns
323
+ -------
324
+ Server.
325
+ """
326
+
327
+ # Get.
328
+ app: FastAPI = request.app
329
+ server = app.extra['server']
330
+
331
+ return server
332
+
333
+
323
334
  class ServerBind(ServerBase, metaclass=StaticMeta):
324
335
  """
325
336
  Server API bind parameter type.
@@ -338,6 +349,8 @@ class ServerBind(ServerBase, metaclass=StaticMeta):
338
349
  JSON = DatabaseORMModel
339
350
  Conn = DatabaseConnectionAsync
340
351
  Sess = DatabaseORMSessionAsync
352
+ Server = Type['rserver.Server']
353
+ server = Depends(depend_server)
341
354
  i = ServerBindInstance()
342
355
  conn = ServerBindInstanceDatabaseConnection()
343
356
  sess = ServerBindInstanceDatabaseSession()
reyserver/rclient.py CHANGED
@@ -9,8 +9,10 @@
9
9
  """
10
10
 
11
11
 
12
- from typing import TypedDict, Literal
12
+ from typing import TypedDict
13
13
  from datetime import datetime as Datetime
14
+ from requests import Response
15
+ from reykit.rbase import copy_type_hints
14
16
  from reykit.ros import File, Folder, overload
15
17
  from reykit.rnet import join_url, request, get_response_file_name
16
18
 
@@ -31,31 +33,40 @@ class ServerClient(ServerBase):
31
33
  """
32
34
 
33
35
 
34
- def __init__(self, url: str) -> None:
36
+ def __init__(
37
+ self,
38
+ username: str,
39
+ password: str,
40
+ url: str = 'http://127.0.0.1:8000',
41
+ ) -> None:
35
42
  """
36
43
  Build instance attributes.
37
44
 
38
45
  Parameters
39
46
  ----------
47
+ username: User name.
48
+ password: User password.
40
49
  url : Server url.
41
50
  """
42
51
 
43
52
  # Build.
53
+ self.username = username
54
+ self.password = password
44
55
  self.url = url
56
+ self.token = self.create_session(username, password)
45
57
 
46
58
 
47
59
  def create_session(
48
60
  self,
49
- account: str,
50
- password: str,
51
- account_type: Literal['name', 'email', 'phone'] = 'name'
61
+ username: str,
62
+ password: str
52
63
  ) -> str:
53
64
  """
54
65
  Create session.
55
66
 
56
67
  Parameters
57
68
  ----------
58
- account : User account, name or email or phone.
69
+ account : User name.
59
70
  password : User password.
60
71
  account_type : User account type.
61
72
 
@@ -67,9 +78,8 @@ class ServerClient(ServerBase):
67
78
  # Parameter.
68
79
  url = join_url(self.url, 'sessions')
69
80
  json = {
70
- 'account': account,
71
- 'password': password,
72
- 'account_type': account_type
81
+ 'account': username,
82
+ 'password': password
73
83
  }
74
84
 
75
85
  # Request.
@@ -80,6 +90,45 @@ class ServerClient(ServerBase):
80
90
  return token
81
91
 
82
92
 
93
+ def _request(self, *args, **kwargs) -> Response:
94
+ """
95
+ Send request.
96
+
97
+ Parameters
98
+ ----------
99
+ args : Position arguments.
100
+ kwargs : Keyword arguments.
101
+
102
+ Returns
103
+ -------
104
+ Response.
105
+ """
106
+
107
+ # Parameter.
108
+ headers = kwargs.setdefault('headers', {})
109
+ headers['Authorization'] = f'Bearer {self.token}'
110
+ kwargs['check'] = list(range(200, 400))
111
+ kwargs['check'].append(401)
112
+
113
+ # Request.
114
+ response = request(*args, **kwargs)
115
+
116
+ # Check.
117
+ if response.status_code != 401:
118
+ return response
119
+
120
+ # Try request.
121
+ self.token = self.create_session(self.username, self.password)
122
+ headers['Authorization'] = f'Bearer {self.token}'
123
+ kwargs['check'] = True
124
+ response = request(*args, **kwargs)
125
+
126
+ return response
127
+
128
+
129
+ request = copy_type_hints(_request, request)
130
+
131
+
83
132
  def upload_file(
84
133
  self,
85
134
  source: str | bytes,
@@ -128,7 +177,7 @@ class ServerClient(ServerBase):
128
177
  # Request.
129
178
  data = {'name': file_name, 'note': note}
130
179
  files = {'file': file_bytes}
131
- response = request(url, data=data, files=files, check=True)
180
+ response = self.request(url, data=data, files=files, check=True)
132
181
 
133
182
  ## Extract.
134
183
  response_json = response.json()
@@ -177,7 +226,7 @@ class ServerClient(ServerBase):
177
226
  url = join_url(self.url, 'files', file_id, 'download')
178
227
 
179
228
  # Request.
180
- response = request(url, check=True)
229
+ response = self.request(url, check=True)
181
230
  file_bytes = response.content
182
231
 
183
232
  # Not save.
@@ -215,7 +264,7 @@ class ServerClient(ServerBase):
215
264
  url = join_url(self.url, 'files', file_id)
216
265
 
217
266
  # Request.
218
- response = request(url, check=True)
267
+ response = self.request(url, check=True)
219
268
  response_dict = response.json()
220
269
 
221
270
  return response_dict
reyserver/rfile.py CHANGED
@@ -14,7 +14,7 @@ from fastapi.responses import FileResponse
14
14
  from reydb import rorm, DatabaseEngine, DatabaseEngineAsync
15
15
  from reykit.ros import FileStore, get_md5
16
16
 
17
- from .rbase import ServerConfig, Bind, exit_api
17
+ from .rbase import Bind, exit_api
18
18
 
19
19
 
20
20
  __all__ = (
@@ -212,7 +212,8 @@ async def upload_file(
212
212
  file: Bind.File = Bind.i.forms,
213
213
  name: str = Bind.i.forms_n,
214
214
  note: str = Bind.i.forms_n,
215
- sess: Bind.Sess = Bind.sess.file
215
+ sess: Bind.Sess = Bind.sess.file,
216
+ server: Bind.Server = Bind.server
216
217
  ) -> DatabaseORMTableInfo:
217
218
  """
218
219
  Upload file.
@@ -229,7 +230,7 @@ async def upload_file(
229
230
  """
230
231
 
231
232
  # Handle parameter.
232
- file_store = FileStore(ServerConfig.server.api_file_dir)
233
+ file_store = FileStore(server.api_file_dir)
233
234
  file_bytes = await file.read()
234
235
  file_md5 = get_md5(file_bytes)
235
236
  file_size = len(file_bytes)
reyserver/rserver.py CHANGED
@@ -16,6 +16,7 @@ from contextlib import asynccontextmanager, _AsyncGeneratorContextManager
16
16
  from uvicorn import run as uvicorn_run
17
17
  from starlette.middleware.base import _StreamingResponse
18
18
  from fastapi import FastAPI, Request
19
+ from fastapi.params import Depends
19
20
  from fastapi.staticfiles import StaticFiles
20
21
  from fastapi.middleware.gzip import GZipMiddleware
21
22
  from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
@@ -23,7 +24,7 @@ from reydb import rorm, DatabaseAsync, DatabaseEngineAsync
23
24
  from reykit.rbase import CoroutineFunctionSimple, Singleton, throw
24
25
  from reykit.rrand import randchar
25
26
 
26
- from .rbase import ServerBase, ServerConfig, Bind
27
+ from .rbase import ServerBase, Bind
27
28
  from . import radmin
28
29
 
29
30
 
@@ -68,6 +69,8 @@ class Server(ServerBase, Singleton):
68
69
  debug : Whether use development mode debug server.
69
70
  """
70
71
 
72
+ from .rauth import depend_auth
73
+
71
74
  # Parameter.
72
75
  if type(ssl_cert) != type(ssl_key):
73
76
  throw(AssertionError, ssl_cert, ssl_key)
@@ -76,13 +79,14 @@ class Server(ServerBase, Singleton):
76
79
  elif iscoroutinefunction(depend):
77
80
  depend = (depend,)
78
81
  depend = [
82
+ Bind.Depend(depend_auth)
83
+ ] + [
79
84
  Bind.Depend(task)
80
85
  for task in depend
81
86
  ]
82
87
  lifespan = self.__create_lifespan(before, after, db_warm)
83
88
 
84
89
  # Build.
85
- ServerConfig.server = self
86
90
  self.db = db
87
91
  self.ssl_cert = ssl_cert
88
92
  self.ssl_key = ssl_key
@@ -91,7 +95,8 @@ class Server(ServerBase, Singleton):
91
95
  self.app = FastAPI(
92
96
  dependencies=depend,
93
97
  lifespan=lifespan,
94
- debug=debug
98
+ debug=debug,
99
+ server=self
95
100
  )
96
101
 
97
102
  if public is not None:
@@ -107,6 +112,8 @@ class Server(ServerBase, Singleton):
107
112
  self.__add_default_middleware()
108
113
 
109
114
  # API.
115
+ self.is_started_auth: bool = False
116
+ 'Whether start authentication.'
110
117
  self.api_auth_key: str
111
118
  'Authentication API JWT encryption key.'
112
119
  self.api_auth_sess_seconds: int
@@ -185,7 +192,7 @@ class Server(ServerBase, Singleton):
185
192
 
186
193
  # Add.
187
194
  @self.wrap_middleware
188
- async def foo(
195
+ async def middleware(
189
196
  request: Request,
190
197
  call_next: Callable[[Request], Coroutine[None, None, _StreamingResponse]]
191
198
  ) -> _StreamingResponse:
@@ -262,6 +269,16 @@ class Server(ServerBase, Singleton):
262
269
  setattr(self.app, key, value)
263
270
 
264
271
 
272
+ def add_api_base(self) -> None:
273
+ """
274
+ Add base API.
275
+ """
276
+ from fastapi import Request
277
+ @self.app.get('/test')
278
+ async def test(request: Request) -> str:
279
+ return 'test'
280
+
281
+
265
282
  def add_api_admin(self) -> None:
266
283
  """
267
284
  Add admin API.
@@ -315,13 +332,14 @@ class Server(ServerBase, Singleton):
315
332
  """
316
333
 
317
334
  from .rauth import (
318
- build_auth_db,
319
- auth_router,
320
335
  DatabaseORMTableUser,
321
336
  DatabaseORMTableRole,
322
337
  DatabaseORMTablePerm,
323
338
  DatabaseORMTableUserRole,
324
- DatabaseORMTableRolePerm
339
+ DatabaseORMTableRolePerm,
340
+ build_auth_db,
341
+ auth_router,
342
+ depend_auth
325
343
  )
326
344
 
327
345
  # Parameter.
@@ -338,6 +356,7 @@ class Server(ServerBase, Singleton):
338
356
  self.api_auth_key = key
339
357
  self.api_auth_sess_seconds = sess_seconds
340
358
  self.app.include_router(auth_router, tags=['auth'])
359
+ self.is_started_auth = True
341
360
 
342
361
  ## Admin.
343
362
  self.add_admin_model(DatabaseORMTableUser, engine, category='auth', name='User', column_list=['user_id', 'name'])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reyserver
3
- Version: 1.1.58
3
+ Version: 1.1.60
4
4
  Summary: Backend server method set.
5
5
  Project-URL: homepage, https://github.com/reyxbo/reyserver/
6
6
  Author-email: Rey <reyxbo@163.com>
@@ -0,0 +1,12 @@
1
+ reyserver/__init__.py,sha256=Oq-lOcQInzhgKt1_4OB2jNx0OO2d9qZg9iZqUx6YRr8,398
2
+ reyserver/radmin.py,sha256=0nOEBd1vFDn0annjiGXi3TN9C6Vofpb8W_UfXj5TuhM,4257
3
+ reyserver/rall.py,sha256=MI1NnqUpq22CK9w3XPPBS0K8lNuf0BnbI0pn4MGMx38,293
4
+ reyserver/rauth.py,sha256=KgHWuRmqmxMoeNFCvCpdxb0S5uv7VH75M0vuMrZTOt8,15111
5
+ reyserver/rbase.py,sha256=kzSbo6yoPlWquR6XiseTKi5hEbllaG3qVmmwnnKKac0,6898
6
+ reyserver/rclient.py,sha256=VDUqQMVUTGzmZ8kjiMet2_zEt0_Siw0gyQkqHRIZ594,6281
7
+ reyserver/rfile.py,sha256=0wS-ohsAOGcSCg07U66wpqJlxnCLWN6gkEQJK4qavWQ,8877
8
+ reyserver/rserver.py,sha256=mjc-SeE2RZZwB5Z1nUSMo_VMign3VcftIK1Kv7XIne8,11484
9
+ reyserver-1.1.60.dist-info/METADATA,sha256=JuZnt-TPamZk_dtV07w4aEm6cT5fZa3Js146QUa6wNI,1666
10
+ reyserver-1.1.60.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
+ reyserver-1.1.60.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
12
+ reyserver-1.1.60.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- reyserver/__init__.py,sha256=Oq-lOcQInzhgKt1_4OB2jNx0OO2d9qZg9iZqUx6YRr8,398
2
- reyserver/radmin.py,sha256=Hwy8QsiQOyK2YP7abcS22IbRKB7sgcDGPHQ2-mHtf-8,3269
3
- reyserver/rall.py,sha256=MI1NnqUpq22CK9w3XPPBS0K8lNuf0BnbI0pn4MGMx38,293
4
- reyserver/rauth.py,sha256=5zQwi7eGjhHD2BHGQDQclLCn3HHg646Q4Cp2Bt6i3uc,11701
5
- reyserver/rbase.py,sha256=_bP_suBPF7dLd4RNKn96-X4ZAEx3vAjMS6vnheCokU4,6617
6
- reyserver/rclient.py,sha256=Ffm66YuWupzEtQ6RqEm2KCc6jSF8JeMB7Xq6pzRFZ6M,5073
7
- reyserver/rfile.py,sha256=CH2uJbBNmBH9ISDirn1LWL5wsjGW5xjB9ZIrdc5UzL0,8864
8
- reyserver/rserver.py,sha256=9-bhgVn_XZ6bvBl4GLdGkUs4UR1TSG08WC3F6ETQo7M,10986
9
- reyserver-1.1.58.dist-info/METADATA,sha256=l98QLYqG9iBeisPA5SgdMpu-aEZll2tWYnG4u7lCgfM,1666
10
- reyserver-1.1.58.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
- reyserver-1.1.58.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
12
- reyserver-1.1.58.dist-info/RECORD,,