diff --git a/server/.idea/misc.xml b/server/.idea/misc.xml
index 5871b5c..f45d3f0 100644
--- a/server/.idea/misc.xml
+++ b/server/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/server/alembic.ini b/server/alembic.ini
index bea7a89..d4aed71 100644
--- a/server/alembic.ini
+++ b/server/alembic.ini
@@ -50,7 +50,7 @@ version_path_separator = os # default: use os.pathsep
# are written from script.py.mako
# output_encoding = utf-8
-sqlalchemy.url = mysql+pymysql://root:1234567890@192.168.137.129/simple_sam
+sqlalchemy.url = mysql+pymysql://root:123456@192.168.137.129/devops
[post_write_hooks]
diff --git a/server/alembic/env.py b/server/alembic/env.py
index aa9436e..b93a82e 100644
--- a/server/alembic/env.py
+++ b/server/alembic/env.py
@@ -19,8 +19,9 @@
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
-from models import *
+from models import *
+from models.internal import *
target_metadata = SQLModel.metadata
diff --git a/server/alembic/script.py.mako b/server/alembic/script.py.mako
index 55df286..3124b62 100644
--- a/server/alembic/script.py.mako
+++ b/server/alembic/script.py.mako
@@ -7,6 +7,7 @@ Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
+import sqlmodel
${imports if imports else ""}
# revision identifiers, used by Alembic.
diff --git a/server/alembic/versions/334040db4d77_delete_sysapi.py b/server/alembic/versions/334040db4d77_delete_sysapi.py
new file mode 100644
index 0000000..0ecc8da
--- /dev/null
+++ b/server/alembic/versions/334040db4d77_delete_sysapi.py
@@ -0,0 +1,53 @@
+"""delete sysapi
+
+Revision ID: 334040db4d77
+Revises: a21539d7fbb7
+Create Date: 2022-10-28 15:00:57.698249
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel
+from sqlalchemy.dialects import mysql
+
+# revision identifiers, used by Alembic.
+revision = '334040db4d77'
+down_revision = 'a21539d7fbb7'
+branch_labels = None
+depends_on = None
+
+
+def upgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_table('menu_apis')
+ op.drop_table('sys_api')
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('menu_apis',
+ sa.Column('menu_id', mysql.INTEGER(), autoincrement=False, nullable=False),
+ sa.Column('api_id', mysql.INTEGER(), autoincrement=False, nullable=False),
+ sa.ForeignKeyConstraint(['api_id'], ['sys_api.id'], name='menu_apis_ibfk_2'),
+ sa.ForeignKeyConstraint(['menu_id'], ['menu.id'], name='menu_apis_ibfk_1'),
+ sa.PrimaryKeyConstraint('menu_id', 'api_id'),
+ mysql_collate='utf8mb4_general_ci',
+ mysql_default_charset='utf8mb4',
+ mysql_engine='InnoDB',
+ mysql_row_format='DYNAMIC'
+ )
+ op.create_table('sys_api',
+ sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False),
+ sa.Column('tags', mysql.VARCHAR(collation='utf8mb4_general_ci', length=10), nullable=False, comment='标签'),
+ sa.Column('path', mysql.VARCHAR(collation='utf8mb4_general_ci', length=50), nullable=False, comment='API路径'),
+ sa.Column('method', mysql.VARCHAR(collation='utf8mb4_general_ci', length=10), nullable=False, comment='HTTP方法'),
+ sa.Column('summary', mysql.VARCHAR(collation='utf8mb4_general_ci', length=20), nullable=False, comment='描述'),
+ sa.Column('deprecated', mysql.TINYINT(display_width=1), server_default=sa.text("'0'"), autoincrement=False, nullable=True, comment='是否废弃'),
+ sa.PrimaryKeyConstraint('id'),
+ mysql_collate='utf8mb4_general_ci',
+ mysql_default_charset='utf8mb4',
+ mysql_engine='InnoDB',
+ mysql_row_format='DYNAMIC'
+ )
+ # ### end Alembic commands ###
diff --git a/server/alembic/versions/a21539d7fbb7_init.py b/server/alembic/versions/a21539d7fbb7_init.py
new file mode 100644
index 0000000..b9ff371
--- /dev/null
+++ b/server/alembic/versions/a21539d7fbb7_init.py
@@ -0,0 +1,35 @@
+"""init
+
+Revision ID: a21539d7fbb7
+Revises:
+Create Date: 2022-10-28 10:38:17.100830
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel
+from sqlalchemy.dialects import mysql
+
+# revision identifiers, used by Alembic.
+revision = 'a21539d7fbb7'
+down_revision = None
+branch_labels = None
+depends_on = None
+
+
+def upgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('user_roles',
+ sa.Column('user_id', sa.Integer(), nullable=False),
+ sa.Column('role_id', sa.Integer(), nullable=False),
+ sa.ForeignKeyConstraint(['role_id'], ['roles.id'], ),
+ sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
+ sa.PrimaryKeyConstraint('user_id', 'role_id')
+ )
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_table('user_roles')
+ # ### end Alembic commands ###
diff --git "a/server/alembic/versions/a5e2cea226d4_\346\267\273\345\212\240\350\217\234\345\215\225\346\216\222\345\272\217\345\255\227\346\256\265.py" "b/server/alembic/versions/a5e2cea226d4_\346\267\273\345\212\240\350\217\234\345\215\225\346\216\222\345\272\217\345\255\227\346\256\265.py"
new file mode 100644
index 0000000..b4b27c0
--- /dev/null
+++ "b/server/alembic/versions/a5e2cea226d4_\346\267\273\345\212\240\350\217\234\345\215\225\346\216\222\345\272\217\345\255\227\346\256\265.py"
@@ -0,0 +1,29 @@
+"""添加菜单排序字段
+
+Revision ID: a5e2cea226d4
+Revises: 334040db4d77
+Create Date: 2022-10-31 09:44:30.289049
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel
+from sqlalchemy.dialects import mysql
+
+# revision identifiers, used by Alembic.
+revision = 'a5e2cea226d4'
+down_revision = '334040db4d77'
+branch_labels = None
+depends_on = None
+
+
+def upgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('menu', sa.Column('sort', sa.Integer(), nullable=True, comment='菜单排序'))
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_column('menu', 'sort')
+ # ### end Alembic commands ###
diff --git "a/server/alembic/versions/b703662d9cf9_\346\233\264\346\226\260\350\217\234\345\215\225\346\216\222\345\272\217\345\255\227\346\256\265.py" "b/server/alembic/versions/b703662d9cf9_\346\233\264\346\226\260\350\217\234\345\215\225\346\216\222\345\272\217\345\255\227\346\256\265.py"
new file mode 100644
index 0000000..1f582ba
--- /dev/null
+++ "b/server/alembic/versions/b703662d9cf9_\346\233\264\346\226\260\350\217\234\345\215\225\346\216\222\345\272\217\345\255\227\346\256\265.py"
@@ -0,0 +1,37 @@
+"""更新菜单排序字段
+
+Revision ID: b703662d9cf9
+Revises: a5e2cea226d4
+Create Date: 2022-10-31 10:22:22.613017
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel
+from sqlalchemy.dialects import mysql
+
+# revision identifiers, used by Alembic.
+revision = 'b703662d9cf9'
+down_revision = 'a5e2cea226d4'
+branch_labels = None
+depends_on = None
+
+
+def upgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.alter_column('menu', 'sort',
+ existing_type=mysql.INTEGER(),
+ type_=sa.Float(),
+ existing_comment='菜单排序',
+ existing_nullable=True)
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.alter_column('menu', 'sort',
+ existing_type=sa.Float(),
+ type_=mysql.INTEGER(),
+ existing_comment='菜单排序',
+ existing_nullable=True)
+ # ### end Alembic commands ###
diff --git a/server/alembic/versions/cc553c35453a_init.py b/server/alembic/versions/cc553c35453a_init.py
deleted file mode 100644
index 969f7dc..0000000
--- a/server/alembic/versions/cc553c35453a_init.py
+++ /dev/null
@@ -1,222 +0,0 @@
-"""init
-
-Revision ID: cc553c35453a
-Revises:
-Create Date: 2022-06-08 14:26:51.364287
-
-"""
-from alembic import op
-import sqlalchemy as sa
-from sqlalchemy.dialects import mysql
-
-# revision identifiers, used by Alembic.
-revision = 'cc553c35453a'
-down_revision = None
-branch_labels = None
-depends_on = None
-
-
-def upgrade() -> None:
- # ### commands auto generated by Alembic - please adjust! ###
- op.drop_index('ix_role_category_category_id', table_name='role_category')
- op.drop_index('ix_role_category_role_id', table_name='role_category')
- op.drop_table('role_category')
- op.drop_table('casbin_rule')
- op.alter_column('assets', 'id',
- existing_type=mysql.BIGINT(),
- nullable=True,
- autoincrement=True)
- op.drop_index('ix_assets_area', table_name='assets')
- op.drop_index('ix_assets_category', table_name='assets')
- op.drop_index('ix_assets_deleted', table_name='assets')
- op.drop_index('ix_assets_id', table_name='assets')
- op.drop_index('ix_assets_manager', table_name='assets')
- op.drop_index('ix_assets_user', table_name='assets')
- op.alter_column('category', 'id',
- existing_type=mysql.INTEGER(),
- nullable=True,
- autoincrement=True)
- op.drop_index('ix_category_alias', table_name='category')
- op.drop_index('ix_category_desc', table_name='category')
- op.drop_index('ix_category_id', table_name='category')
- op.drop_index('ix_category_name', table_name='category')
- op.alter_column('category_field', 'id',
- existing_type=mysql.INTEGER(),
- nullable=True,
- autoincrement=True)
- op.drop_index('ix_category_field_category_id', table_name='category_field')
- op.drop_index('ix_category_field_desc', table_name='category_field')
- op.drop_index('ix_category_field_id', table_name='category_field')
- op.drop_index('ix_category_field_multi', table_name='category_field')
- op.drop_index('ix_category_field_name', table_name='category_field')
- op.drop_index('ix_category_field_need', table_name='category_field')
- op.drop_index('ix_category_field_show', table_name='category_field')
- op.drop_index('ix_category_field_type', table_name='category_field')
- op.alter_column('menu', 'id',
- existing_type=mysql.INTEGER(),
- nullable=True,
- autoincrement=True)
- op.drop_index('ix_menu_component', table_name='menu')
- op.drop_index('ix_menu_enable', table_name='menu')
- op.drop_index('ix_menu_id', table_name='menu')
- op.drop_index('ix_menu_name', table_name='menu')
- op.drop_index('ix_menu_parent_id', table_name='menu')
- op.drop_index('ix_menu_path', table_name='menu')
- op.drop_index('ix_menu_type', table_name='menu')
- op.drop_index('ix_role_menu_menu_id', table_name='role_menu')
- op.drop_index('ix_role_menu_role_id', table_name='role_menu')
- op.alter_column('roles', 'id',
- existing_type=mysql.INTEGER(),
- nullable=True,
- autoincrement=True)
- op.drop_index('ix_roles_description', table_name='roles')
- op.drop_index('ix_roles_enable', table_name='roles')
- op.drop_index('ix_roles_id', table_name='roles')
- op.drop_index('ix_roles_name', table_name='roles')
- op.alter_column('sys_api', 'id',
- existing_type=mysql.INTEGER(),
- nullable=True,
- autoincrement=True)
- op.alter_column('system', 'id',
- existing_type=mysql.INTEGER(),
- nullable=True,
- autoincrement=True)
- op.drop_index('ix_system_admin', table_name='system')
- op.drop_index('ix_system_cpu', table_name='system')
- op.drop_index('ix_system_developer', table_name='system')
- op.drop_index('ix_system_env', table_name='system')
- op.drop_index('ix_system_host', table_name='system')
- op.drop_index('ix_system_id', table_name='system')
- op.drop_index('ix_system_ip', table_name='system')
- op.drop_index('ix_system_memory', table_name='system')
- op.drop_index('ix_system_project', table_name='system')
- op.drop_index('ix_system_storage', table_name='system')
- op.drop_index('ix_system_system', table_name='system')
- op.drop_index('ix_system_type', table_name='system')
- op.alter_column('user', 'name',
- existing_type=mysql.VARCHAR(charset='utf8mb4', collation='utf8mb4_general_ci', length=50),
- nullable=False)
- op.alter_column('user', 'id',
- existing_type=mysql.INTEGER(),
- nullable=True,
- autoincrement=True)
- op.drop_index('ix_user_email', table_name='user')
- op.drop_index('ix_user_name', table_name='user')
- op.drop_index('name', table_name='user')
- op.drop_index('ix_user_roles_role_id', table_name='user_roles')
- op.drop_index('ix_user_roles_user_id', table_name='user_roles')
- # ### end Alembic commands ###
-
-
-def downgrade() -> None:
- # ### commands auto generated by Alembic - please adjust! ###
- op.create_index('ix_user_roles_user_id', 'user_roles', ['user_id'], unique=False)
- op.create_index('ix_user_roles_role_id', 'user_roles', ['role_id'], unique=False)
- op.create_index('name', 'user', ['name', 'email'], unique=False)
- op.create_index('ix_user_name', 'user', ['name'], unique=False)
- op.create_index('ix_user_email', 'user', ['email'], unique=False)
- op.alter_column('user', 'id',
- existing_type=mysql.INTEGER(),
- nullable=False,
- autoincrement=True)
- op.alter_column('user', 'name',
- existing_type=mysql.VARCHAR(charset='utf8mb4', collation='utf8mb4_general_ci', length=50),
- nullable=True)
- op.create_index('ix_system_type', 'system', ['type'], unique=False)
- op.create_index('ix_system_system', 'system', ['system'], unique=False)
- op.create_index('ix_system_storage', 'system', ['storage'], unique=False)
- op.create_index('ix_system_project', 'system', ['project'], unique=False)
- op.create_index('ix_system_memory', 'system', ['memory'], unique=False)
- op.create_index('ix_system_ip', 'system', ['ip'], unique=False)
- op.create_index('ix_system_id', 'system', ['id'], unique=False)
- op.create_index('ix_system_host', 'system', ['host'], unique=False)
- op.create_index('ix_system_env', 'system', ['env'], unique=False)
- op.create_index('ix_system_developer', 'system', ['developer'], unique=False)
- op.create_index('ix_system_cpu', 'system', ['cpu'], unique=False)
- op.create_index('ix_system_admin', 'system', ['admin'], unique=False)
- op.alter_column('system', 'id',
- existing_type=mysql.INTEGER(),
- nullable=False,
- autoincrement=True)
- op.alter_column('sys_api', 'id',
- existing_type=mysql.INTEGER(),
- nullable=False,
- autoincrement=True)
- op.create_index('ix_roles_name', 'roles', ['name'], unique=False)
- op.create_index('ix_roles_id', 'roles', ['id'], unique=False)
- op.create_index('ix_roles_enable', 'roles', ['enable'], unique=False)
- op.create_index('ix_roles_description', 'roles', ['description'], unique=False)
- op.alter_column('roles', 'id',
- existing_type=mysql.INTEGER(),
- nullable=False,
- autoincrement=True)
- op.create_index('ix_role_menu_role_id', 'role_menu', ['role_id'], unique=False)
- op.create_index('ix_role_menu_menu_id', 'role_menu', ['menu_id'], unique=False)
- op.create_index('ix_menu_type', 'menu', ['type'], unique=False)
- op.create_index('ix_menu_path', 'menu', ['path'], unique=False)
- op.create_index('ix_menu_parent_id', 'menu', ['parent_id'], unique=False)
- op.create_index('ix_menu_name', 'menu', ['name'], unique=False)
- op.create_index('ix_menu_id', 'menu', ['id'], unique=False)
- op.create_index('ix_menu_enable', 'menu', ['enable'], unique=False)
- op.create_index('ix_menu_component', 'menu', ['component'], unique=False)
- op.alter_column('menu', 'id',
- existing_type=mysql.INTEGER(),
- nullable=False,
- autoincrement=True)
- op.create_index('ix_category_field_type', 'category_field', ['type'], unique=False)
- op.create_index('ix_category_field_show', 'category_field', ['show'], unique=False)
- op.create_index('ix_category_field_need', 'category_field', ['need'], unique=False)
- op.create_index('ix_category_field_name', 'category_field', ['name'], unique=False)
- op.create_index('ix_category_field_multi', 'category_field', ['multi'], unique=False)
- op.create_index('ix_category_field_id', 'category_field', ['id'], unique=False)
- op.create_index('ix_category_field_desc', 'category_field', ['desc'], unique=False)
- op.create_index('ix_category_field_category_id', 'category_field', ['category_id'], unique=False)
- op.alter_column('category_field', 'id',
- existing_type=mysql.INTEGER(),
- nullable=False,
- autoincrement=True)
- op.create_index('ix_category_name', 'category', ['name'], unique=False)
- op.create_index('ix_category_id', 'category', ['id'], unique=False)
- op.create_index('ix_category_desc', 'category', ['desc'], unique=False)
- op.create_index('ix_category_alias', 'category', ['alias'], unique=False)
- op.alter_column('category', 'id',
- existing_type=mysql.INTEGER(),
- nullable=False,
- autoincrement=True)
- op.create_index('ix_assets_user', 'assets', ['user'], unique=False)
- op.create_index('ix_assets_manager', 'assets', ['manager'], unique=False)
- op.create_index('ix_assets_id', 'assets', ['id'], unique=False)
- op.create_index('ix_assets_deleted', 'assets', ['deleted'], unique=False)
- op.create_index('ix_assets_category', 'assets', ['category'], unique=False)
- op.create_index('ix_assets_area', 'assets', ['area'], unique=False)
- op.alter_column('assets', 'id',
- existing_type=mysql.BIGINT(),
- nullable=False,
- autoincrement=True)
- op.create_table('casbin_rule',
- sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False),
- sa.Column('ptype', mysql.VARCHAR(collation='utf8mb4_general_ci', length=255), nullable=True),
- sa.Column('v0', mysql.VARCHAR(collation='utf8mb4_general_ci', length=255), nullable=True),
- sa.Column('v1', mysql.VARCHAR(collation='utf8mb4_general_ci', length=255), nullable=True),
- sa.Column('v2', mysql.VARCHAR(collation='utf8mb4_general_ci', length=255), nullable=True),
- sa.Column('v3', mysql.VARCHAR(collation='utf8mb4_general_ci', length=255), nullable=True),
- sa.Column('v4', mysql.VARCHAR(collation='utf8mb4_general_ci', length=255), nullable=True),
- sa.Column('v5', mysql.VARCHAR(collation='utf8mb4_general_ci', length=255), nullable=True),
- sa.PrimaryKeyConstraint('id'),
- mysql_collate='utf8mb4_general_ci',
- mysql_default_charset='utf8mb4',
- mysql_engine='InnoDB'
- )
- op.create_table('role_category',
- sa.Column('role_id', mysql.INTEGER(), autoincrement=False, nullable=False),
- sa.Column('category_id', mysql.INTEGER(), autoincrement=False, nullable=False),
- sa.ForeignKeyConstraint(['category_id'], ['category.id'], name='role_category_ibfk_2'),
- sa.ForeignKeyConstraint(['role_id'], ['roles.id'], name='role_category_ibfk_1'),
- sa.PrimaryKeyConstraint('role_id', 'category_id'),
- mysql_collate='utf8mb4_general_ci',
- mysql_default_charset='utf8mb4',
- mysql_engine='InnoDB'
- )
- op.create_index('ix_role_category_role_id', 'role_category', ['role_id'], unique=False)
- op.create_index('ix_role_category_category_id', 'role_category', ['category_id'], unique=False)
- # ### end Alembic commands ###
diff --git a/server/common/auth_casbin.py b/server/common/auth_casbin.py
new file mode 100644
index 0000000..d6fcb69
--- /dev/null
+++ b/server/common/auth_casbin.py
@@ -0,0 +1,16 @@
+from fastapi import Request, HTTPException
+from ..settings import casbin_enforcer
+
+
+class Authority:
+ def __init__(self, policy: str):
+ self.policy = policy
+
+ def __call__(self, request: Request):
+ if request.state.uid == 1:
+ # uid为1的都跳过,为admin用户
+ return True
+ model, act = self.policy.split(':')
+ if not casbin_enforcer.enforce(f'uid_{request.state.uid}', model, act):
+ print('没有权限')
+ raise HTTPException(status_code=403, detail="没有权限")
diff --git a/server/db.py b/server/common/database.py
similarity index 81%
rename from server/db.py
rename to server/common/database.py
index 67c1264..0aefca4 100644
--- a/server/db.py
+++ b/server/common/database.py
@@ -1,8 +1,5 @@
from sqlmodel import create_engine, SQLModel, Session, select
-
-SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:1234567890@192.168.137.129/simple_sam"
-
-engine = create_engine(SQLALCHEMY_DATABASE_URL, future=False)
+from ..settings import engine
def init_db():
@@ -34,4 +31,4 @@ def get_or_create(session: Session, model, **kwargs):
instance = model(**kwargs)
session.add(instance)
session.commit()
- return instance
\ No newline at end of file
+ return instance
diff --git a/server/common/security.py b/server/common/security.py
index ee83c94..da41a28 100644
--- a/server/common/security.py
+++ b/server/common/security.py
@@ -1,22 +1,45 @@
from datetime import datetime, timedelta
+from fastapi import Request, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
+from fastapi.security.utils import get_authorization_scheme_param
from jose import JWTError, jwt
from passlib.context import CryptContext
-from typing import Optional
+from ..settings import settings
# to get a string like this run:
# openssl rand -hex 32
-SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
-ALGORITHM = "HS256"
-ACCESS_TOKEN_EXPIRE_MINUTES = 30
+
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
-def hash_password(password):
- return pwd_context.hash(password)
+def auth_check(request: Request):
+ """
+ 检查是否有token信息,并在request.state中添加uid值
+ :param request:
+ :return:
+ """
+ for url in settings.NO_VERIFY_URL:
+ if url == request.url.path.lower():
+ print(f"{request.url.path} 在白名单中,不需要权限验证")
+ return True
+ authorization: str = request.headers.get("Authorization")
+ schema, param = get_authorization_scheme_param(authorization)
+ if not authorization or schema.lower() != "bearer":
+ raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Not authenticated")
+
+ try:
+ playload = jwt.decode(param, settings.SECRET_KEY, settings.ALGORITHM)
+ except jwt.ExpiredSignatureError as e:
+ raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e))
+ except JWTError as e:
+ raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e))
+
+ uid = playload.get('uid')
+ # 在Request对象中设置用户对象,这样在其他地方就能通过request.state.uid获取当前用户id了
+ request.state.uid = uid
def create_access_token(data):
@@ -25,34 +48,12 @@ def create_access_token(data):
:param data:
:return:
"""
- expires_delta = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
+ expires_delta = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
- encoded_jwt = token_encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
+ encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
return encoded_jwt
-
-
-def token_encode(to_encode, secret_key, algorithm):
- """
- token加密
- :param to_encode:
- :param secret_key:
- :param algorithm:
- :return:
- """
- return jwt.encode(to_encode, secret_key, algorithm)
-
-
-def token_decode(token, secret_key=SECRET_KEY, algorithm=ALGORITHM):
- """
- token解密
- :param token:
- :param secret_key:
- :param algorithm:
- :return:
- """
- return jwt.decode(token, secret_key, algorithm)
diff --git a/server/crud/internal/__init__.py b/server/crud/internal/__init__.py
index 590d67e..a7c086d 100644
--- a/server/crud/internal/__init__.py
+++ b/server/crud/internal/__init__.py
@@ -1,4 +1,3 @@
from .user import user
from .roles import role
from .menu import menu
-from .sysapi import api
diff --git a/server/crud/internal/menu.py b/server/crud/internal/menu.py
index 7ad51e5..1429fbb 100644
--- a/server/crud/internal/menu.py
+++ b/server/crud/internal/menu.py
@@ -1,6 +1,6 @@
from typing import Optional, List
from sqlmodel import Session, select
-from server.models.internal.menu import Menu
+from ...models.internal.menu import Menu
from ..base import CRUDBase
@@ -9,6 +9,7 @@ def search(self, session: Session, q: Optional = None) -> List[Menu]:
sql = select(self.model)
if q is not None:
sql = sql.where(self.model.name.like(f'%{q}%'))
+ sql = sql.order_by(self.model.sort)
return session.exec(sql).all()
def update(self, session: Session, db_obj, obj_in: Menu):
diff --git a/server/crud/internal/roles.py b/server/crud/internal/roles.py
index 5b82d6a..db0b49a 100644
--- a/server/crud/internal/roles.py
+++ b/server/crud/internal/roles.py
@@ -2,7 +2,7 @@
from sqlmodel import select, Session
from ...models.internal import Role, Menu, RoleMenu
from ..base import CRUDBase
-from ...dependencies import casbin_enforcer
+from ...settings import casbin_enforcer
class CRUDRole(CRUDBase[Role]):
@@ -49,11 +49,10 @@ def update_menus(self, session: Session, db_obj: Role, menus: List[int]):
casbin_enforcer.delete_permissions_for_user(f'role_{db_obj.id}')
print(db_menus)
for menu in db_menus:
- if len(menu.apis) == 0:
- continue
- for api in menu.apis:
- print(f'增加权限:role_{db_obj.id},{api.path},{api.method}')
- casbin_enforcer.add_permission_for_user(f'role_{db_obj.id}', api.path, api.method)
+ if menu.auth is not None:
+ model, act = menu.auth.split(':')
+ print(f'增加权限:role_{db_obj.id},{model},{act}')
+ casbin_enforcer.add_permission_for_user(f'role_{db_obj.id}', model, act)
session.add(db_obj)
session.commit()
session.refresh(db_obj)
diff --git a/server/crud/internal/sysapi.py b/server/crud/internal/sysapi.py
deleted file mode 100644
index ea2fa67..0000000
--- a/server/crud/internal/sysapi.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import List, Union
-from sqlmodel import select, Session, or_
-from ...models.internal import Api
-from ..base import CRUDBase
-
-
-class CRUDAPI(CRUDBase[Api]):
- def get_multi(self, db: Session, id: List[int]) -> List[Api]:
- return db.exec(select(self.model).where(self.model.id.in_(id))).all()
-
- def get_tree(self, db: Session):
- tags = db.exec(select(self.model.tags).distinct(self.model.tags)).all()
- print(tags)
- tree_apis = []
- for tag in tags:
- child_apis = db.exec(select(self.model.id, self.model.summary).where(self.model.tags == tag)).all()
- tree_apis.append({'label': tag, 'options': child_apis})
- return tree_apis
-
-
-api = CRUDAPI(Api)
diff --git a/server/db_init.py b/server/db_init.py
index 0863780..040290a 100644
--- a/server/db_init.py
+++ b/server/db_init.py
@@ -1,2 +1,18 @@
-from sqlmodel import create_engine
-from .sql.models import *
+from sqlmodel import Session
+from .db import init_db, engine
+from .models.role import Role
+from .models.user import User
+
+
+def main():
+ init_db()
+ with Session(engine) as session:
+ admin_role = Role(name='admin', description='Admin管理员组', enable=1)
+ admin = User(name='admin', enable=1, password='1111111')
+ admin.roles.append(admin_role)
+ session.add(admin)
+ session.commit()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/server/dependencies.py b/server/dependencies.py
deleted file mode 100644
index 4afbf49..0000000
--- a/server/dependencies.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import json
-import base64
-from typing import Optional, Dict, Any
-from fastapi import Header, HTTPException, Depends, Request, APIRouter
-from .common.security import token_decode
-from jose.exceptions import JWTError, ExpiredSignatureError
-from .db import engine
-import casbin_sqlalchemy_adapter
-import casbin
-
-
-async def check_token(token: str = Header(..., alias="Authorization")):
- # 传递过来的token信息格式:Bearer token,所以需要匹配
- token = token[7:]
- try:
- token_info = token_decode(token)
- except ExpiredSignatureError as e:
- raise HTTPException(status_code=401, detail=str(e))
- except JWTError as e:
- raise HTTPException(status_code=401, detail=str(e))
- print(token_info)
- return token_info
-
-
-def check_uid(token: dict = Depends(check_token)):
- """
- 角色检查
- :param token:
- :return:
- """
- uid = token['uid']
- return uid
-
-
-class PermissionCheck:
- def __init__(self, enforcer):
- self.e: casbin.Enforcer = enforcer
-
- def __call__(self, request: Request, uid: int = Depends(check_uid)):
- print('permission check')
- request_permission = f"{request.method}:{request.url.path}"
- print(request_permission)
- if self.e.enforce(f'uid_{uid}', request.url.path, request.method):
- print('拥有权限')
- return True
- else:
- print('没有权限')
- raise HTTPException(status_code=403, detail="没有权限")
-
-
-adapter = casbin_sqlalchemy_adapter.Adapter(engine)
-casbin_enforcer = casbin.Enforcer('server/model.conf', adapter)
-
-check_permission = PermissionCheck(casbin_enforcer)
diff --git a/server/main.py b/server/main.py
index d679f1f..a7b9bbf 100644
--- a/server/main.py
+++ b/server/main.py
@@ -1,18 +1,16 @@
from sqlmodel import Session
from fastapi import FastAPI, Depends
-from .routers.internal import api, login, user, menu, roles
-from .dependencies import check_permission
-from .models.internal.api import Api
-from .db import engine, get_or_create
+from .routers.internal import login, user, menu, roles
+from .common.security import auth_check
+from .settings import engine
-app = FastAPI()
+app = FastAPI(dependencies=[Depends(auth_check)])
# 不执行check_permission的,表示不需要权限验证
app.include_router(login.router, tags=['用户登录'])
-app.include_router(user.router, tags=['用户管理'], dependencies=[Depends(check_permission)])
-app.include_router(menu.router, tags=['菜单管理'], dependencies=[Depends(check_permission)])
-app.include_router(roles.router, tags=['角色管理'], dependencies=[Depends(check_permission)])
-app.include_router(api.router, tags=['接口管理'], dependencies=[Depends(check_permission)])
+app.include_router(user.router, tags=['用户管理'])
+app.include_router(menu.router, tags=['菜单管理'])
+app.include_router(roles.router, tags=['角色管理'])
@app.on_event("startup")
@@ -23,24 +21,6 @@ def startup():
"""
print('服务启动后执行服务')
print('API接口更新')
- with Session(engine) as session:
- for url, value in app.openapi()['paths'].items():
- if 'get' in value:
- method = 'get'
- tags = value[method]['tags'][0]
- get_or_create(session, Api, tags=tags, path=url, method='GET', summary=value[method]['summary'])
- if 'post' in value:
- method = 'post'
- tags = value[method]['tags'][0]
- get_or_create(session, Api, tags=tags, path=url, method='POST', summary=value[method]['summary'])
- if 'put' in value:
- method = 'put'
- tags = value[method]['tags'][0]
- get_or_create(session, Api, tags=tags, path=url, method='PUT', summary=value[method]['summary'])
- if 'delete' in value:
- method = 'delete'
- tags = value[method]['tags'][0]
- get_or_create(session, Api, tags=tags, path=url, method='DELETE', summary=value[method]['summary'])
@app.on_event("shutdown")
diff --git a/server/models/internal/__init__.py b/server/models/internal/__init__.py
index 004377f..efb0daf 100644
--- a/server/models/internal/__init__.py
+++ b/server/models/internal/__init__.py
@@ -1,4 +1,3 @@
from .user import User
from .menu import Menu
from .role import Role, RoleMenu
-from .api import Api
diff --git a/server/models/internal/api.py b/server/models/internal/api.py
deleted file mode 100644
index 4de6128..0000000
--- a/server/models/internal/api.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import List, TYPE_CHECKING
-from sqlmodel import SQLModel, Field, Relationship, Column, Integer
-from .relationships import MenuApis
-
-if TYPE_CHECKING:
- from .menu import Menu
-
-
-class ApiBase(SQLModel):
- tags: str = Field(max_length=10, sa_column_kwargs={'comment': '标签'})
- path: str = Field(max_length=50, sa_column_kwargs={'comment': 'API路径'})
- method: str = Field(max_length=10, sa_column_kwargs={'comment': 'HTTP方法'})
- summary: str = Field(max_length=20, sa_column_kwargs={'comment': '描述'})
- deprecated: bool = Field(default=False, sa_column_kwargs={'comment': '是否废弃'})
-
-
-class Api(ApiBase, table=True):
- __tablename__ = 'sys_api'
- id: int = Field(sa_column=Column('id', Integer, primary_key=True, autoincrement=True))
- menus: List['Menu'] = Relationship(back_populates='apis', link_model=MenuApis)
-
-
-class ApiWithMenus(ApiBase):
- id: int
- menus: List['Menu'] = []
diff --git a/server/models/internal/menu.py b/server/models/internal/menu.py
index 0fc912c..183bfcc 100644
--- a/server/models/internal/menu.py
+++ b/server/models/internal/menu.py
@@ -1,6 +1,6 @@
-from typing import Optional, List, Any, TYPE_CHECKING
+from typing import Optional, List
from sqlmodel import SQLModel, Field, Relationship, Column, Boolean, Integer
-from .relationships import RoleMenu, MenuApis
+from .relationships import RoleMenu
class MenuBase(SQLModel):
@@ -8,35 +8,23 @@ class MenuBase(SQLModel):
name: str = Field(max_length=20, sa_column_kwargs={'comment': '菜单名'})
path: Optional[str] = Field(max_length=100, sa_column_kwargs={'comment': '路径'})
component: Optional[str] = Field(max_length=50, sa_column_kwargs={'comment': '组件'})
+ auth: Optional[str] = Field(max_length=50, sa_column_kwargs={'comment': '授权标识'})
type: str = Field(max_length=10, sa_column_kwargs={'comment': '类型'})
parent_id: Optional[int] = Field(sa_column_kwargs={'comment': '父级ID'})
+ sort: Optional[float] = Field(sa_column_kwargs={'comment': '菜单排序'})
enable: bool = Field(default=True, sa_column=Column(Boolean, comment='启用'))
class Menu(MenuBase, table=True):
roles: List["Role"] = Relationship(back_populates="menus", link_model=RoleMenu)
- apis: List['Api'] = Relationship(back_populates='menus', link_model=MenuApis)
# apis: List['Api'] = Relationship(back_populates="menus", link_model=MenuApi)
-class MenuRead(MenuBase):
- apis: List['Api'] = []
-
-
class MenusWithChild(MenuBase):
- apis: List['Api'] = []
children: List['MenusWithChild'] = []
-class MenuWithUpdate(MenuBase):
- # 更新菜单信息
- # id: Optional[int]
- apis: List[int] = []
-
-
# 底部导入,且延迟注释
from .role import Role
-from .api import Api
MenusWithChild.update_forward_refs()
-MenuRead.update_forward_refs()
diff --git a/server/models/internal/relationships.py b/server/models/internal/relationships.py
index 8603065..1a4188f 100644
--- a/server/models/internal/relationships.py
+++ b/server/models/internal/relationships.py
@@ -14,8 +14,3 @@ class UserRole(SQLModel, table=True):
user_id: int = Field(foreign_key="user.id", primary_key=True)
role_id: int = Field(foreign_key="roles.id", primary_key=True)
-
-class MenuApis(SQLModel, table=True):
- __tablename__ = 'menu_apis'
- menu_id: int = Field(foreign_key='menu.id', primary_key=True)
- api_id: int = Field(foreign_key='sys_api.id', primary_key=True)
diff --git a/server/routers/internal/api.py b/server/routers/internal/api.py
deleted file mode 100644
index be499de..0000000
--- a/server/routers/internal/api.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from typing import Optional
-from sqlmodel import Session
-from fastapi import APIRouter, Depends
-from ...db import get_session
-from ... import crud
-from ...schemas.internal.pagination import Pagination
-from ...schemas.internal.sysapi import ApiSearch
-
-router = APIRouter(prefix='/api', )
-
-
-@router.post('/sysapis/search', summary='获取API列表')
-async def get_sysapis(search: Pagination[ApiSearch],
- session: Session = Depends(get_session)):
- print(search)
- total = crud.internal.api.search_total(session, search.search)
- print(total)
- sys_apis = crud.internal.api.search(session, search)
- return {
- 'total': total,
- 'data': sys_apis
- }
-
-
-@router.get('/sysapis/{id}', summary='获取指定API', deprecated=True)
-async def get_test(q: Optional[str] = None, direction: str = 'next', id: Optional[int] = 0,
- limit: Optional[int] = None, offset_page: Optional[int] = None,
- session: Session = Depends(get_session)):
- total = crud.internal.api.search_total(session, q)
- print(total)
- sysapis = crud.internal.api.search(session, q, direction, id, limit, offset_page)
- # users_list = [api for api in sysapis]
- # print(users_list)
- return {
- 'total': total,
- 'data': sysapis
- }
diff --git a/server/routers/internal/login.py b/server/routers/internal/login.py
index 45c75cb..1727659 100644
--- a/server/routers/internal/login.py
+++ b/server/routers/internal/login.py
@@ -1,7 +1,6 @@
from typing import List
-from fastapi import APIRouter, Depends
-from ...dependencies import check_token
-from ...db import get_session
+from fastapi import APIRouter, Depends, Request
+from ...common.database import get_session
from sqlmodel import Session, select
from sqlalchemy.exc import NoResultFound
from ...common.security import create_access_token
@@ -43,28 +42,34 @@ async def login(login_form: UserLogin, session: Session = Depends(get_session)):
@router.get('/permission', summary='获取权限')
-async def get_permission(session: Session = Depends(get_session), token: dict = Depends(check_token)):
+async def get_permission(request: Request, session: Session = Depends(get_session)):
"""
用户权限请求,返回拥有权限的菜单列表,前端根据返回的菜单列表信息,合成菜单项
:param session:
:param token:
:return:
"""
- uid: List[int] = token['uid']
+ uid: int = request.state.uid
print(f"uid is:{uid}")
user: User = crud.internal.user.get(session, uid)
print(user.roles)
user_menus = []
# admin组用户获取所有菜单列表
- if crud.internal.role.check_admin(session, uid):
- menu_list = session.exec(select(Menu)).all()
+ if uid == 1 or crud.internal.role.check_admin(session, uid):
+ menu_list = session.exec(select(Menu).where(Menu.type != 'btn').order_by(Menu.sort)).all()
+ btn_list = session.exec(select(Menu.auth).where(Menu.type == 'btn').where(Menu.auth.is_not(None))).all()
else:
for role in user.roles:
user_menus.extend([menu.id for menu in role.menus])
- menu_list = session.exec(select(Menu).where(Menu.id.in_(set(user_menus)))).all()
+ menu_list = session.exec(
+ select(Menu).where(Menu.id.in_(set(user_menus))).where(Menu.type != 'btn').order_by(Menu.sort)).all()
+ btn_list = session.exec(select(Menu.auth).where(Menu.id.in_(set(user_menus))).where(Menu.type == 'btn')).all()
print('menulist')
print(menu_list)
user_menus = menu_convert(menu_list)
print(user_menus)
- return user_menus
+ return {
+ 'menus': user_menus,
+ 'btns': btn_list
+ }
diff --git a/server/routers/internal/menu.py b/server/routers/internal/menu.py
index 43107a0..517c70e 100644
--- a/server/routers/internal/menu.py
+++ b/server/routers/internal/menu.py
@@ -1,13 +1,12 @@
-from copy import deepcopy
from typing import Optional, List
from fastapi import APIRouter, Depends, status, HTTPException
from sqlmodel import Session
-from ...db import get_session
-from ...models.internal.menu import Menu, MenusWithChild, MenuWithUpdate, MenuRead
-from ...models.internal.api import Api, ApiWithMenus
+from ...common.database import get_session
+from ...common.auth_casbin import Authority
+from ...models.internal.menu import MenuBase, Menu, MenusWithChild
from ...common import utils
from ... import crud
-from ...dependencies import casbin_enforcer
+from ...settings import casbin_enforcer
router = APIRouter(prefix='/api')
@@ -16,41 +15,27 @@
async def get_all_menu(q: Optional[str] = None, session: Session = Depends(get_session)):
# 复用crud.get_menu_list,默认role为admin就是返回所有的菜单列表
menu_list: List[Menu] = crud.menu.search(session, q)
- menu_list_apis: List[MenuRead] = []
- for menu in menu_list:
- new_menu = MenuRead(**menu.dict(), apis=menu.apis)
- menu_list_apis.append(new_menu)
- user_menus = utils.menu_convert(menu_list_apis)
+ user_menus = utils.menu_convert(menu_list)
return user_menus
-@router.get('/menus/tree_apis', summary='获取树形菜单接口')
-async def get_menu_apis(session: Session = Depends(get_session)):
- apis = crud.internal.api.get_tree(session)
- print(apis)
- return apis
-
-
-@router.post('/menus', summary="新建菜单", response_model=Menu)
-async def add_menu(menu: MenuWithUpdate, session: Session = Depends(get_session)):
+@router.post('/menus', summary="新建菜单", response_model=Menu, dependencies=[Depends(Authority("menu:add"))])
+async def add_menu(menu: MenuBase, session: Session = Depends(get_session)):
"""
# 新建的菜单,还是没有授权给角色的,所以直接新增就行了
:param menu:
:param session:
:return:
"""
- apis: List[Api] = crud.internal.api.get_multi(session, menu.apis)
- delattr(menu, "apis")
db_obj = crud.menu.insert(session, Menu(**menu.dict()))
- db_obj.apis = apis
session.add(db_obj)
session.commit()
session.refresh(db_obj)
return db_obj
-@router.put('/menus', summary="更新菜单")
-async def update_menu(menu: MenuWithUpdate, session: Session = Depends(get_session)):
+@router.put('/menus', summary="更新菜单", dependencies=[Depends(Authority("menu:update"))])
+async def update_menu(menu: MenuBase, session: Session = Depends(get_session)):
"""
更新菜单,涉及到原菜单对应api的更新,则需要更新对应信息
:param menu:
@@ -58,32 +43,15 @@ async def update_menu(menu: MenuWithUpdate, session: Session = Depends(get_sessi
:return:
"""
db_obj: Menu = crud.menu.get(session, menu.id)
- old_apis: List[ApiWithMenus] = []
- for api in db_obj.apis:
- tmp_api = ApiWithMenus(**api.dict())
- tmp_api.menus = [menu.id for menu in api.menus]
- old_apis.append(tmp_api)
- print('old_apis is:')
- print(old_apis)
- apis: List[Api] = crud.internal.api.get_multi(session, menu.apis)
- delattr(menu, "apis")
new_obj: Menu = crud.menu.update(session, db_obj, menu)
- print(apis)
- new_obj.apis = apis
- for role in new_obj.roles:
- for api in old_apis:
- if len(api.menus) > 1:
- continue
- casbin_enforcer.delete_permission_for_user(f'role_{role.id}', api.path, api.method)
- for api in apis:
- casbin_enforcer.add_permission_for_user(f'role_{role.id}', api.path, api.method)
session.add(new_obj)
session.commit()
session.refresh(new_obj)
return new_obj
-@router.delete('/menus/{id}', summary='删除菜单', status_code=status.HTTP_204_NO_CONTENT)
+@router.delete('/menus/{id}', summary='删除菜单', status_code=status.HTTP_204_NO_CONTENT,
+ dependencies=[Depends(Authority("menu:del"))])
async def del_menu(id: int, session: Session = Depends(get_session)):
db_obj = crud.menu.get(session, id)
if len(db_obj.roles) > 0:
diff --git a/server/routers/internal/roles.py b/server/routers/internal/roles.py
index 969f621..580c760 100644
--- a/server/routers/internal/roles.py
+++ b/server/routers/internal/roles.py
@@ -2,8 +2,8 @@
from fastapi import APIRouter, Depends, status
from fastapi.exceptions import HTTPException
from sqlmodel import Session
-from ...dependencies import check_permission
-from ...db import get_session
+from ...common.auth_casbin import Authority
+from ...common.database import get_session
from ... import crud
from ...models.internal import Role, Menu
from ...models.internal.role import RoleWithMenus, RoleInsert, RoleUpdate
@@ -11,7 +11,7 @@
from ...schemas.internal.roles import RoleSearch
from ...common.utils import menu_convert
-router = APIRouter(prefix='/api', dependencies=[Depends(check_permission), ])
+router = APIRouter(prefix='/api')
@router.get('/roles/enable-menus', summary='获取角色菜单')
@@ -48,7 +48,7 @@ async def get_roles(search: Pagination[RoleSearch], session: Session = Depends(g
}
-@router.post('/roles', summary="新建角色")
+@router.post('/roles', summary="新建角色", dependencies=[Depends(Authority('role:add'))])
async def add_roles(role_info: RoleInsert, session: Session = Depends(get_session)):
print(role_info)
enable_menus = role_info.menus
@@ -58,7 +58,7 @@ async def add_roles(role_info: RoleInsert, session: Session = Depends(get_sessio
return db_obj
-@router.put('/roles', summary="更新角色")
+@router.put('/roles', summary="更新角色", dependencies=[Depends(Authority('role:update'))])
async def update_roles(role_info: RoleUpdate, session: Session = Depends(get_session)):
print(role_info)
if role_info.name == 'admin':
@@ -71,7 +71,8 @@ async def update_roles(role_info: RoleUpdate, session: Session = Depends(get_ses
return db_obj
-@router.delete('/roles/{id}', summary='删除角色', status_code=status.HTTP_204_NO_CONTENT)
+@router.delete('/roles/{id}', summary='删除角色', dependencies=[Depends(Authority('role:del'))],
+ status_code=status.HTTP_204_NO_CONTENT)
async def del_role(id: int, session: Session = Depends(get_session)):
db_obj = crud.internal.role.get(session, id)
if db_obj.name == 'admin':
diff --git a/server/routers/internal/user.py b/server/routers/internal/user.py
index 10fc226..52d980f 100644
--- a/server/routers/internal/user.py
+++ b/server/routers/internal/user.py
@@ -2,8 +2,9 @@
from sqlmodel import Session, select
from sqlalchemy.exc import NoResultFound
from fastapi import APIRouter, Depends, status, HTTPException
-from ...dependencies import casbin_enforcer
-from ...db import get_session
+from ...settings import casbin_enforcer
+from ...common.auth_casbin import Authority
+from ...common.database import get_session
from ...models.internal import User, Role
from ...models.internal.user import UserCreateWithRoles, UserReadWithRoles, UserUpdateWithRoles, UserUpdatePassword, \
UserWithOutPasswd
@@ -14,7 +15,7 @@
@router.get('/users/roles', summary='获取角色')
-async def get_roles(id: Optional[int] = None, session: Session = Depends(get_session, )):
+async def get_roles(id: Optional[int] = None, session: Session = Depends(get_session)):
if id is None:
# 添加新用户时无用户id
roles = []
@@ -69,7 +70,7 @@ async def get_all_user(search: Pagination[UserWithOutPasswd],
}
-@router.post('/users', summary="新建用户")
+@router.post('/users', summary="新建用户",dependencies=[Depends(Authority("user:add"))])
async def update_user(user_info: UserCreateWithRoles, session: Session = Depends(get_session)):
"""
更新用户信息的所有操作,可涉及更新用户名、密码、角色等
@@ -85,13 +86,13 @@ async def update_user(user_info: UserCreateWithRoles, session: Session = Depends
return user
-@router.put('/users/password', summary='重置密码')
+@router.put('/users/password', summary='重置密码', dependencies=[Depends(Authority('user:reset'))])
async def update_password(user: UserUpdatePassword, session: Session = Depends(get_session)):
crud.internal.user.update_passwd(session, uid=user.id, passwd=user.password)
@router.put('/users/{uid}',
- summary='更新用户', status_code=status.HTTP_204_NO_CONTENT)
+ summary='更新用户', dependencies=[Depends(Authority("user:update"))],status_code=status.HTTP_204_NO_CONTENT)
async def update_user(uid: int, user_info: UserUpdateWithRoles, session: Session = Depends(get_session)):
"""
更新用户信息的所有操作,可涉及更新用户名、密码、角色等
@@ -110,7 +111,7 @@ async def update_user(uid: int, user_info: UserUpdateWithRoles, session: Session
return user
-@router.delete('/users/{uid}', summary='删除用户', status_code=status.HTTP_204_NO_CONTENT)
+@router.delete('/users/{uid}', summary='删除用户',dependencies=[Depends(Authority("user:del"))], status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(uid: int, session: Session = Depends(get_session)):
try:
user = session.exec(select(User).where(User.id == uid)).one()
diff --git a/server/settings.py b/server/settings.py
new file mode 100644
index 0000000..ef76e5e
--- /dev/null
+++ b/server/settings.py
@@ -0,0 +1,29 @@
+import casbin_sqlalchemy_adapter
+import casbin
+from typing import List
+from pathlib import Path
+from pydantic import BaseSettings
+from sqlmodel import create_engine
+
+
+class APISettings(BaseSettings):
+ # token加密相关参数
+ SECRET_KEY: str = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
+ ALGORITHM: str = "HS256"
+ ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
+
+ CASBIN_MODEL_PATH: str = "server/model.conf"
+ # sql数据库信息
+ DATABASE_URI = "mysql+pymysql://root:123456@192.168.137.129/devops"
+ # 白名单,不需要进行任何验证即可访问
+ NO_VERIFY_URL: List = [
+ '/',
+ '/api/login',
+ ]
+
+
+settings = APISettings()
+
+engine = create_engine(settings.DATABASE_URI, future=False)
+adapter = casbin_sqlalchemy_adapter.Adapter(engine)
+casbin_enforcer = casbin.Enforcer(settings.CASBIN_MODEL_PATH, adapter)
diff --git a/www/src/App.vue b/www/src/App.vue
index 9489f83..df8366c 100644
--- a/www/src/App.vue
+++ b/www/src/App.vue
@@ -1,54 +1,59 @@
-
-
-
-
+
+
+
diff --git a/www/src/api/menus.js b/www/src/api/menus.js
index 82289f6..9f34511 100644
--- a/www/src/api/menus.js
+++ b/www/src/api/menus.js
@@ -5,5 +5,4 @@ export const GetAllMenus = (q) => GET('/api/menus', { q })
export const PostNewMenu = (menu) => POST('/api/menus', menu )
export const PutMenu = (menu) => PUT('/api/menus', menu)
export const DeleteMenu = (id) => DELETE('/api/menus/' + id)
-export const GetMenuApis = (id) => GET('/api/menus/' + id + '/apis')
-export const GetMenuTreeApis = () => GET('/api/menus/tree_apis')
\ No newline at end of file
+export const GetMenuApis = (id) => GET('/api/menus/' + id + '/apis')
\ No newline at end of file
diff --git a/www/src/composables/useMenu.js b/www/src/composables/useMenu.js
index c170e57..6b3cb65 100644
--- a/www/src/composables/useMenu.js
+++ b/www/src/composables/useMenu.js
@@ -2,25 +2,12 @@ import {reactive, ref, watch, computed} from 'vue'
export default function (form, menuData, emit) {
const selectData = reactive(form)
- const selectApis = ref([])
-
- if (selectData.id !== null) {
- for (const api of selectData.apis) {
- console.log(api)
- selectApis.value.push(api.id)
- }
- }
watch(selectData, (newData) => {
console.log('watch selectData change:' + selectData)
- selectData.apis = selectApis.value
emit('update:form', selectData)
})
- watch(selectApis, (newValue) => {
- console.log('selectApi watch')
- selectData.apis = selectApis.value
- })
const menuMap = (arr) => {
const menu = arr.filter(item => item.type !== 'btn')
@@ -40,7 +27,6 @@ export default function (form, menuData, emit) {
return {
selectData,
- selectApis,
cascaderMenu
}
}
\ No newline at end of file
diff --git a/www/src/router/index.js b/www/src/router/index.js
index dc78c1d..3461ec9 100644
--- a/www/src/router/index.js
+++ b/www/src/router/index.js
@@ -2,57 +2,58 @@ import {createRouter, createWebHistory} from 'vue-router'
export const constantRouterMap = [
- {
- path: '/',
- name: 'home',
- component: () => import('@/views/Layout'),
- },
- {
- path: '/dashboard',
- name: 'dashboard',
- component: ()=>import('@/views/Layout'),
- children:[
- {
- path:'',
- component: ()=>import('@/views/DashBoard')
- }
- ]
- },
- {
- path: '/login',
- component: () => import('@/views/Login/index'),
- // hidden: true
- },
- {
- path: '/404',
- component: () => import('@/views/errorPage/404'),
- hidden: true
- },
- {
- path: '/401',
- component: () => import('@/views/errorPage/401'),
- hidden: true
- },
+ {
+ path: '/',
+ name: 'home',
+ component: () => import('@/views/Layout'),
+ },
+ {
+ path: '/dashboard',
+ name: 'dashboard',
+ component: () => import('@/views/Layout'),
+ children: [
+ {
+ path: '',
+ component: () => import('@/views/DashBoard')
+ }
+ ]
+ },
+ {
+ path: '/login',
+ component: () => import('@/views/Login/index'),
+ // hidden: true
+ },
+ // {
+ // path: '/404',
+ // name: 'notFound',
+ // component: () => import('@/views/errorPage/NotFound'),
+ // hidden: true
+ // },
+ // {
+ // path:'/:patchMatch(.*)*',
+ // name:'not-found',
+ // redirect:'/404'
+ // }
- // {
- // path: '/user',
- // component: Layout,
- // hidden: true,
- // redirect: 'noredirect',
- // children: [
- // {
- // path: 'center',
- // component: () => import('@/views/system/user/center'),
- // name: '个人中心',
- // meta: { title: '个人中心', icon: 'user' }
- // }
- // ]
- // }
- // { path: '*', redirect: '/404', hidden: true }
+ // {
+ // path: '/user',
+ // component: Layout,
+ // hidden: true,
+ // redirect: 'noredirect',
+ // children: [
+ // {
+ // path: 'center',
+ // component: () => import('@/views/system/user/center'),
+ // name: '个人中心',
+ // meta: { title: '个人中心', icon: 'user' }
+ // }
+ // ]
+ // }
+ // { path: '*', redirect: '/404', hidden: true }
]
export default createRouter({
- history: createWebHistory(),
- // scrollBehavior: () => ({ y: 0 }),
- routes: constantRouterMap
+ history: createWebHistory(),
+ // scrollBehavior: () => ({ y: 0 }),
+ routes: constantRouterMap
})
\ No newline at end of file
diff --git a/www/src/stores/index.js b/www/src/stores/index.js
index 00f18fe..a7f443d 100644
--- a/www/src/stores/index.js
+++ b/www/src/stores/index.js
@@ -17,31 +17,10 @@ export const useStore = defineStore('user', {
name: '',
avatar: '',
asyncRoutes: [],
+ buttons:[],
}
},
- getters: {
- buttons(state) {
- let btns = []
-
- function findAllBtn(list) {
- list.forEach(val => {
- if (val.type !== 'btn') {
- if (val.children && val.children.length > 0) {
- findAllBtn(val.children)
- }
- } else {
- btns.push(val.path)
- }
- })
- }
-
- findAllBtn(state.asyncRoutes)
- console.log('button:')
- console.log(btns)
- return btns
- },
- },
actions: {
//执行登录请求,获取token
@@ -88,7 +67,8 @@ export const useStore = defineStore('user', {
GetUserPermission().then(response => {
console.log('permission response is:')
console.log(response)
- this.asyncRoutes = response
+ this.asyncRoutes = response.menus
+ this.buttons = response.btns
resolve(response)
}).catch(error => {
reject(error)
diff --git a/www/src/views/Layout.vue b/www/src/views/Layout.vue
index b3f95d0..9869db8 100644
--- a/www/src/views/Layout.vue
+++ b/www/src/views/Layout.vue
@@ -19,7 +19,7 @@