diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e8ecb4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/ +.venv/ \ No newline at end of file diff --git a/CMS_Django_Backend.zip b/CMS_Django_Backend.zip new file mode 100644 index 0000000..9ad9b30 Binary files /dev/null and b/CMS_Django_Backend.zip differ diff --git a/CMS_Django_Backend/__init__.py b/CMS_Django_Backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/CMS_Django_Backend/__pycache__/__init__.cpython-311.pyc b/CMS_Django_Backend/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..cd2958a Binary files /dev/null and b/CMS_Django_Backend/__pycache__/__init__.cpython-311.pyc differ diff --git a/CMS_Django_Backend/__pycache__/settings.cpython-311.pyc b/CMS_Django_Backend/__pycache__/settings.cpython-311.pyc new file mode 100644 index 0000000..6a7f801 Binary files /dev/null and b/CMS_Django_Backend/__pycache__/settings.cpython-311.pyc differ diff --git a/CMS_Django_Backend/__pycache__/urls.cpython-311.pyc b/CMS_Django_Backend/__pycache__/urls.cpython-311.pyc new file mode 100644 index 0000000..ce5de87 Binary files /dev/null and b/CMS_Django_Backend/__pycache__/urls.cpython-311.pyc differ diff --git a/CMS_Django_Backend/__pycache__/wsgi.cpython-311.pyc b/CMS_Django_Backend/__pycache__/wsgi.cpython-311.pyc new file mode 100644 index 0000000..7444898 Binary files /dev/null and b/CMS_Django_Backend/__pycache__/wsgi.cpython-311.pyc differ diff --git a/CMS_Django_Backend/asgi.py b/CMS_Django_Backend/asgi.py new file mode 100644 index 0000000..872eac3 --- /dev/null +++ b/CMS_Django_Backend/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for CMS_Django_Backend project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CMS_Django_Backend.settings') + +application = get_asgi_application() diff --git a/CMS_Django_Backend/settings.py b/CMS_Django_Backend/settings.py new file mode 100644 index 0000000..a269c72 --- /dev/null +++ b/CMS_Django_Backend/settings.py @@ -0,0 +1,143 @@ +""" +Django settings for CMS_Django_Backend project. + +Generated by 'django-admin startproject' using Django 5.1. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-mm$)j^vw#wtb$%f2m-=p@4d4ziy^-_zv^t21(i@9j+7+#eqzby' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + +# Application definition + +INSTALLED_APPS = [ + # 'django.contrib.admin', + # 'django.contrib.auth', + 'django.contrib.contenttypes', + # 'django.contrib.sessions', + # 'django.contrib.messages', + 'django.contrib.staticfiles', + 'apps.auth.apps.AuthConfig', + 'apps.api.apps.ApiConfig', + 'apps.home.apps.HomeConfig', +] + +MIDDLEWARE = [ + # 'django.middleware.security.SecurityMiddleware', + # 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + # 'django.contrib.auth.middleware.AuthenticationMiddleware', + # 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'CMS_Django_Backend.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [BASE_DIR / 'templates'] + , + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'CMS_Django_Backend.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'data/db.sqlite3', + }, + 'cypher': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'data/db_cypher.sqlite3', + } +} + +# Password validation +# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +# Internationalization +# https://docs.djangoproject.com/en/5.1/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.1/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +# session设置 +# 设置会话cookie的有效期(默认为两周) +# SESSION_COOKIE_AGE = 1209600 # 2 weeks, in seconds + +# 设置会话cookie的过期时间(默认为False,表示关闭浏览器时失效) +SESSION_EXPIRE_AT_BROWSER_CLOSE = True + +# 如果设置了True,每次用户会话更新时,会话cookie的过期时间都会被更新 +SESSION_SAVE_EVERY_REQUEST = False + +import os + +# 配置 MEDIA_ROOT 作为你上传文件在服务器中的基本路径 +MEDIA_ROOT = os.path.join(BASE_DIR, 'upload') # 注意此处不要写成列表或元组的形式 + +# 配置 MEDIA_URL 作为公用 URL,指向上传文件的基本路径 +MEDIA_URL = '/media/' diff --git a/CMS_Django_Backend/urls.py b/CMS_Django_Backend/urls.py new file mode 100644 index 0000000..a5ce684 --- /dev/null +++ b/CMS_Django_Backend/urls.py @@ -0,0 +1,30 @@ +""" +URL configuration for CMS_Django_Backend project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from django.conf import settings +from django.conf.urls.static import static +from apps.home import views as home_views + +urlpatterns = [ + # path('admin/', admin.site.urls), + # path('login', include('apps.login.urls')), + # path('auth', include('apps.auth.urls')), + path('home/', home_views.home, name='home'), + path('api/', include('apps.api.urls')), + path('auth/', include('apps.auth.urls')), +] + static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT) diff --git a/CMS_Django_Backend/wsgi.py b/CMS_Django_Backend/wsgi.py new file mode 100644 index 0000000..9087073 --- /dev/null +++ b/CMS_Django_Backend/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for CMS_Django_Backend project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CMS_Django_Backend.settings') + +application = get_wsgi_application() diff --git a/README.md b/README.md index d3becb2..02abd39 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ -# CMS_Django_Backend +## CMS_Django_Backend + +CMS后端 -CMS管理系统后台 \ No newline at end of file diff --git a/apps/api/__init__.py b/apps/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/api/__pycache__/__init__.cpython-311.pyc b/apps/api/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..2bc0fb4 Binary files /dev/null and b/apps/api/__pycache__/__init__.cpython-311.pyc differ diff --git a/apps/api/__pycache__/apps.cpython-311.pyc b/apps/api/__pycache__/apps.cpython-311.pyc new file mode 100644 index 0000000..bc42f2b Binary files /dev/null and b/apps/api/__pycache__/apps.cpython-311.pyc differ diff --git a/apps/api/__pycache__/common.cpython-311.pyc b/apps/api/__pycache__/common.cpython-311.pyc new file mode 100644 index 0000000..46ccadc Binary files /dev/null and b/apps/api/__pycache__/common.cpython-311.pyc differ diff --git a/apps/api/__pycache__/config.cpython-311.pyc b/apps/api/__pycache__/config.cpython-311.pyc new file mode 100644 index 0000000..6a57947 Binary files /dev/null and b/apps/api/__pycache__/config.cpython-311.pyc differ diff --git a/apps/api/__pycache__/models.cpython-311.pyc b/apps/api/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000..2c7b127 Binary files /dev/null and b/apps/api/__pycache__/models.cpython-311.pyc differ diff --git a/apps/api/__pycache__/urls.cpython-311.pyc b/apps/api/__pycache__/urls.cpython-311.pyc new file mode 100644 index 0000000..ac1528b Binary files /dev/null and b/apps/api/__pycache__/urls.cpython-311.pyc differ diff --git a/apps/api/__pycache__/views.cpython-311.pyc b/apps/api/__pycache__/views.cpython-311.pyc new file mode 100644 index 0000000..562b07e Binary files /dev/null and b/apps/api/__pycache__/views.cpython-311.pyc differ diff --git a/apps/api/admin.py b/apps/api/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/apps/api/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/api/apps.py b/apps/api/apps.py new file mode 100644 index 0000000..ae75201 --- /dev/null +++ b/apps/api/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ApiConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.api' diff --git a/apps/api/common.py b/apps/api/common.py new file mode 100644 index 0000000..46825fd --- /dev/null +++ b/apps/api/common.py @@ -0,0 +1,125 @@ +import re + + +class CaesarCypherClass: + """ + 恺撒密码,提供以恺撒密码方法进行加密及解密的方法,加密方法使用CaesarEncode()函数,解密方法使用CaesarDecode()函数 + """ + + def __init__(self, *args, **kwargs): + pass + + @staticmethod + def caesar_encode(s): + """ + 恺撒密码加密方法,需要提供需要加密的明文。 + """ + s_encode = '' + for c in s: + if 'a' <= c <= 'z': + s_encode += chr(ord('a') + (ord(c) - ord('a') + 3) % 26) + elif 'A' <= c <= 'Z': + s_encode += chr(ord('A') + (ord(c) - ord('A') + 3) % 26) + elif 0x4E00 <= ord(c) <= 0x9FA5: + s_encode += chr(ord(c) + 3) + elif '0' <= c <= '9': + s_encode += chr(ord('0') + (ord(c) - ord('0') + 3) % 10) + else: + s_encode += c + return s_encode + + @staticmethod + def caesar_decode(s): + """ + 恺撒密码解密方法,需要提供需要解密的密文。 + """ + s_decode = '' + for c in s: + if 'a' <= c <= 'z': + s_decode += chr(ord('a') + (ord(c) - ord('a') - 3) % 26) + elif 'A' <= c <= 'Z': + s_decode += chr(ord('A') + (ord(c) - ord('A') - 3) % 26) + elif 0x4E00 <= ord(c) <= 0x9FA5: + s_decode += chr(ord(c) - 3) + elif '0' <= c <= '9': + s_decode += chr(ord('0') + (ord(c) - ord('0') - 3) % 10) + else: + s_decode += c + return s_decode + + +class Base64CypherClass: + """ + Base64的加解密算法,最简单的加密方式,可加密短的文字、小图片、小文件,图片文件大小不宜超过10M + """ + def __init__(self, *args, **kwargs): + """ + Base64类初始化函数 + :param args: + :param kwargs: + """ + import importlib + self.base64 = importlib.import_module('base64') + self.os = importlib.import_module('os') + self.time = importlib.import_module('time') + self.re = importlib.import_module('re') + + @staticmethod + def base64_encode_str(self, s): + """ + Base64字符串加密 + :param self: + :param s: 要加密的字符串 + :return: 加密后的字符串 + """ + return self.base64.b64encode(s.encode('utf-8')) + + @staticmethod + def base64_decode_str(self, s): + """ + Base64字符串解密,解密前先判断是否为Base64加密方式 + :param self: + :param s: 要解密的字符串 + :return: 解密后的字符串 + """ + try: + self.base64.b64decode(s) + return self.base64.b64decode(s).decode('utf-8') + except Exception as e: + return f"base64解密失败,请确定加密方式是否正确。错误信息:{e}" + + @staticmethod + def base64_encode_pic(self, pic): + """ + Base64加密图片,路径不存在则返回"图片路径不存在" + :param self: + :param pic: 要加密的图片路径 + :return: 返回加密的base64字符 + """ + if self.os.path.exists(pic): + with open(pic, 'rb') as f: + read_pic = open(pic, 'rb') + read_data = read_pic.read() + read_pic.close() + return self.base64.b64encode(read_data) + else: + return "图片路径不存在" + + @staticmethod + def base64_decode_pic(self, pic_bs64): + """ + Base64解密图片 + :param self: + :param pic_bs64: + :return: 返回图片路径 + """ + pic_path = f"upload/temp/pic{int(self.time.time())}" + if self.os.path.exists(f"{pic_path}.jpg"): + self.os.remove(f"{pic_path}.jpg") + elif not self.os.path.exists("upload/temp/pic"): + self.os.path.mkdir("upload/temp/pic") + + with open(f"{pic_path}.jpg", 'wb') as f: + f.write(self.base64.b64decode(pic_bs64)) + + return f"{pic_path}.jpg" diff --git a/apps/api/config.py b/apps/api/config.py new file mode 100644 index 0000000..1315252 --- /dev/null +++ b/apps/api/config.py @@ -0,0 +1,8 @@ +class Config: + config = { + "isCypher": False, + "CypherMethod": "base64" + } + + def getconfig(self, config_name): + return self.config[config_name] diff --git a/apps/api/migrations/0001_initial.py b/apps/api/migrations/0001_initial.py new file mode 100644 index 0000000..1b662fa --- /dev/null +++ b/apps/api/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 5.1 on 2024-08-18 14:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='SysConfig', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, unique=True, verbose_name='id')), + ('name', models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='名称')), + ('identity', models.CharField(blank=True, max_length=100, null=True, verbose_name='标识')), + ('param', models.CharField(blank=True, max_length=200, null=True, verbose_name='参数')), + ('desc', models.CharField(max_length=500, verbose_name='描述')), + ('create_by', models.CharField(max_length=50, verbose_name='创建人')), + ('create_time', models.DateTimeField(verbose_name='创建时间')), + ('update_by', models.CharField(max_length=50, verbose_name='更新人')), + ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ], + options={ + 'verbose_name': '系统配置表', + }, + ), + ] diff --git a/apps/api/migrations/__init__.py b/apps/api/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/api/migrations/__pycache__/0001_initial.cpython-311.pyc b/apps/api/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..5ce3cae Binary files /dev/null and b/apps/api/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/apps/api/migrations/__pycache__/0002_alter_sysconfig_options.cpython-311.pyc b/apps/api/migrations/__pycache__/0002_alter_sysconfig_options.cpython-311.pyc new file mode 100644 index 0000000..311493d Binary files /dev/null and b/apps/api/migrations/__pycache__/0002_alter_sysconfig_options.cpython-311.pyc differ diff --git a/apps/api/migrations/__pycache__/__init__.cpython-311.pyc b/apps/api/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..2c2b0cd Binary files /dev/null and b/apps/api/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/apps/api/models.py b/apps/api/models.py new file mode 100644 index 0000000..36b9bd7 --- /dev/null +++ b/apps/api/models.py @@ -0,0 +1,24 @@ +from django.db import models + + +# Create your models here. +class SysConfig(models.Model): + """ + 系统配置表 + """ + id = models.AutoField(verbose_name="id", primary_key=True, unique=True) + name = models.CharField(max_length=50, unique=True, verbose_name="名称", null=True, blank=True) + identity = models.CharField(max_length=100, verbose_name="标识", null=True, blank=True) + param = models.CharField(max_length=200, verbose_name="参数", null=True, blank=True) + desc = models.CharField(max_length=500, verbose_name="描述") + create_by = models.CharField(verbose_name="创建人", max_length=50) + create_time = models.DateTimeField(verbose_name="创建时间") + update_by = models.CharField(verbose_name="更新人", max_length=50) + update_time = models.DateTimeField(verbose_name="更新时间", auto_now=True) + + def __str__(self): + return self.name + + class Meta: + verbose_name = "系统配置表" + diff --git a/apps/api/tests.py b/apps/api/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/apps/api/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/api/urls.py b/apps/api/urls.py new file mode 100644 index 0000000..aeafe34 --- /dev/null +++ b/apps/api/urls.py @@ -0,0 +1,6 @@ +from django.urls import path +from apps.api import views + +urlpatterns = [ + path("getconfig/", views.get_config, name="getconfig"), +] diff --git a/apps/api/views.py b/apps/api/views.py new file mode 100644 index 0000000..f24f988 --- /dev/null +++ b/apps/api/views.py @@ -0,0 +1,44 @@ +from django.shortcuts import HttpResponse +from apps.api import models as m_api +from django.views.decorators.http import require_http_methods, require_POST, require_GET +from apps.api.common import CaesarCypherClass, Base64CypherClass +from apps.api.config import Config + +config = Config() +caesar = CaesarCypherClass() +base64 = Base64CypherClass() + + +# Create your views here. +@require_POST +def get_config(request): + """ + 获取系统配置的接口,通过identity标识字段查询param参数并返回,如果使用加密版数据库则根据加密方式进行解密后返回 + :param request: identity标识字段 + :return: 获取到的参数param + """ + try: + identity = request.POST.get("param") + if config.getconfig("isCypher"): # 启用加密数据库 + param_base64 = m_api.SysConfig.objects.using("cypher").filter(identity=identity).first().param + if config.getconfig("CypherMethod") == "caesar": # 加密方式为Caesar + param = caesar.caesar_decode(param_base64) + return HttpResponse(param) + else: # 加密方式为Base64 + param = base64.base64_decode_str(base64, param_base64) + return HttpResponse(param) + else: # 不加密的数据库 + param = m_api.SysConfig.objects.using("default").filter(identity=identity).first().param + return HttpResponse(param) + except Exception as e: + print(f"报错了:{e}") + return HttpResponse(f"报错了:{e}") + + +@require_POST +def add_config(request): + try: + pass + except Exception as e: + print(f"报错了:{e}") + return HttpResponse(f"报错了:{e}") diff --git a/apps/auth/__init__.py b/apps/auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/auth/__pycache__/__init__.cpython-311.pyc b/apps/auth/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..2d36a05 Binary files /dev/null and b/apps/auth/__pycache__/__init__.cpython-311.pyc differ diff --git a/apps/auth/__pycache__/apps.cpython-311.pyc b/apps/auth/__pycache__/apps.cpython-311.pyc new file mode 100644 index 0000000..39ca4e9 Binary files /dev/null and b/apps/auth/__pycache__/apps.cpython-311.pyc differ diff --git a/apps/auth/__pycache__/models.cpython-311.pyc b/apps/auth/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000..918d2ba Binary files /dev/null and b/apps/auth/__pycache__/models.cpython-311.pyc differ diff --git a/apps/auth/__pycache__/urls.cpython-311.pyc b/apps/auth/__pycache__/urls.cpython-311.pyc new file mode 100644 index 0000000..e7985e1 Binary files /dev/null and b/apps/auth/__pycache__/urls.cpython-311.pyc differ diff --git a/apps/auth/__pycache__/views.cpython-311.pyc b/apps/auth/__pycache__/views.cpython-311.pyc new file mode 100644 index 0000000..55f734e Binary files /dev/null and b/apps/auth/__pycache__/views.cpython-311.pyc differ diff --git a/apps/auth/admin.py b/apps/auth/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/apps/auth/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/auth/apps.py b/apps/auth/apps.py new file mode 100644 index 0000000..263ccf1 --- /dev/null +++ b/apps/auth/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AuthConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.auth' diff --git a/apps/auth/migrations/0001_initial.py b/apps/auth/migrations/0001_initial.py new file mode 100644 index 0000000..866e3a1 --- /dev/null +++ b/apps/auth/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 5.1 on 2024-08-18 14:07 + +import apps.auth.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, unique=True, verbose_name='id')), + ('username', models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='用户名')), + ('pwd', models.CharField(blank=True, max_length=1000, null=True, verbose_name='密码')), + ('email', models.EmailField(max_length=100, verbose_name='电子邮件')), + ('phone', models.CharField(blank=True, max_length=11, null=True, verbose_name='手机')), + ('create_time', models.DateTimeField(verbose_name='注册时间')), + ('avatar', models.ImageField(upload_to=apps.auth.models.user_directory_path, verbose_name='头像')), + ('last_login_time', models.DateTimeField(auto_now=True, verbose_name='最后登录时间')), + ], + options={ + 'verbose_name': '用户表', + }, + ), + ] diff --git a/apps/auth/migrations/0002_menu_role_rolemenu_roleuser.py b/apps/auth/migrations/0002_menu_role_rolemenu_roleuser.py new file mode 100644 index 0000000..82c9c95 --- /dev/null +++ b/apps/auth/migrations/0002_menu_role_rolemenu_roleuser.py @@ -0,0 +1,52 @@ +# Generated by Django 5.1 on 2024-09-17 09:09 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Menu', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, unique=True, verbose_name='id')), + ('menu_name', models.CharField(max_length=50, verbose_name='菜单名称')), + ('parent_id', models.IntegerField(max_length=50, verbose_name='父菜单')), + ('path', models.CharField(max_length=128, verbose_name='路由地址')), + ('order', models.IntegerField(default=0, max_length=5, verbose_name='排序')), + ('create_time', models.DateTimeField(verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, verbose_name='最后更新时间')), + ], + ), + migrations.CreateModel( + name='Role', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, unique=True, verbose_name='id')), + ('role_name', models.CharField(max_length=50, verbose_name='角色名称')), + ('role_name_en', models.CharField(max_length=50, verbose_name='角色英文名称')), + ('create_time', models.DateTimeField(verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, verbose_name='最后更新时间')), + ], + ), + migrations.CreateModel( + name='RoleMenu', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, unique=True, verbose_name='id')), + ('menu_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.menu', verbose_name='菜单ID')), + ('role_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.role', verbose_name='角色ID')), + ], + ), + migrations.CreateModel( + name='RoleUser', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False, unique=True, verbose_name='id')), + ('role_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.role', verbose_name='角色ID')), + ('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.user', verbose_name='用户ID')), + ], + ), + ] diff --git a/apps/auth/migrations/0003_alter_menu_order_alter_menu_parent_id.py b/apps/auth/migrations/0003_alter_menu_order_alter_menu_parent_id.py new file mode 100644 index 0000000..f0eaf2b --- /dev/null +++ b/apps/auth/migrations/0003_alter_menu_order_alter_menu_parent_id.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1 on 2024-09-17 09:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0002_menu_role_rolemenu_roleuser'), + ] + + operations = [ + migrations.AlterField( + model_name='menu', + name='order', + field=models.IntegerField(default=0, verbose_name='排序'), + ), + migrations.AlterField( + model_name='menu', + name='parent_id', + field=models.IntegerField(verbose_name='父菜单'), + ), + ] diff --git a/apps/auth/migrations/__init__.py b/apps/auth/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/auth/migrations/__pycache__/0001_initial.cpython-311.pyc b/apps/auth/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..c1135b2 Binary files /dev/null and b/apps/auth/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/apps/auth/migrations/__pycache__/0002_menu_role_rolemenu_roleuser.cpython-311.pyc b/apps/auth/migrations/__pycache__/0002_menu_role_rolemenu_roleuser.cpython-311.pyc new file mode 100644 index 0000000..186878e Binary files /dev/null and b/apps/auth/migrations/__pycache__/0002_menu_role_rolemenu_roleuser.cpython-311.pyc differ diff --git a/apps/auth/migrations/__pycache__/0003_alter_menu_order_alter_menu_parent_id.cpython-311.pyc b/apps/auth/migrations/__pycache__/0003_alter_menu_order_alter_menu_parent_id.cpython-311.pyc new file mode 100644 index 0000000..f25c474 Binary files /dev/null and b/apps/auth/migrations/__pycache__/0003_alter_menu_order_alter_menu_parent_id.cpython-311.pyc differ diff --git a/apps/auth/migrations/__pycache__/__init__.cpython-311.pyc b/apps/auth/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..8156bcd Binary files /dev/null and b/apps/auth/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/apps/auth/models.py b/apps/auth/models.py new file mode 100644 index 0000000..e38e8fa --- /dev/null +++ b/apps/auth/models.py @@ -0,0 +1,67 @@ +from django.conf.global_settings import MEDIA_ROOT +from django.db import models +import os + + +def user_directory_path(instance, filename): + ext = filename.split('.').pop() + filename = '{0}{1}.{2}'.format(instance.username, instance.phone, ext) + return os.path.join("avatar", filename) # 系统路径分隔符差异,增强代码重用性 + + +# Create your models here. +class User(models.Model): + """ + 用户表 + """ + id = models.AutoField(verbose_name="id", primary_key=True, unique=True) + username = models.CharField(max_length=50, unique=True, verbose_name="用户名", null=True, blank=True) + pwd = models.CharField(max_length=1000, verbose_name="密码", null=True, blank=True) + email = models.EmailField(max_length=100, verbose_name="电子邮件") + phone = models.CharField(max_length=11, verbose_name="手机", null=True, blank=True) + create_time = models.DateTimeField(verbose_name="注册时间") + avatar = models.ImageField(verbose_name="头像", upload_to=user_directory_path) + last_login_time = models.DateTimeField(verbose_name="最后登录时间", auto_now=True) + + def __str__(self): + return self.username + + class Meta: + verbose_name = '用户表' + + # 这里定义一个方法,作用是当用户注册时没有上传照片,模板中调用 [ModelName].[ImageFieldName].url 时赋予一个默认路径 + def avatar_url(self): + if self.avatar and hasattr(self.avatar, 'url'): + return self.avatar.url + else: + return '/media/avatar/default.jpg' + + +class Menu(models.Model): + id = models.AutoField(verbose_name="id", primary_key=True, unique=True) + menu_name = models.CharField(verbose_name="菜单名称", max_length=50, null=False, blank=False) + parent_id = models.IntegerField(verbose_name="父菜单") + path = models.CharField(verbose_name="路由地址", max_length=128) + order = models.IntegerField(verbose_name="排序", default=0) + create_time = models.DateTimeField(verbose_name="创建时间") + update_time = models.DateTimeField(verbose_name="最后更新时间", auto_now=True) + + +class Role(models.Model): + id = models.AutoField(verbose_name="id", primary_key=True, unique=True) + role_name = models.CharField(verbose_name="角色名称", max_length=50, null=False, blank=False) + role_name_en = models.CharField(verbose_name="角色英文名称", max_length=50) + create_time = models.DateTimeField(verbose_name="创建时间") + update_time = models.DateTimeField(verbose_name="最后更新时间", auto_now=True) + + +class RoleMenu(models.Model): + id = models.AutoField(verbose_name="id", primary_key=True, unique=True) + menu_id = models.ForeignKey(verbose_name="菜单ID", to="Menu", to_field="id", on_delete=models.CASCADE) + role_id = models.ForeignKey(verbose_name="角色ID", to="Role", to_field="id", on_delete=models.CASCADE) + + +class RoleUser(models.Model): + id = models.AutoField(verbose_name="id", primary_key=True, unique=True) + role_id = models.ForeignKey(verbose_name="角色ID", to="Role", to_field="id", on_delete=models.CASCADE) + user_id = models.ForeignKey(verbose_name="用户ID", to="User", to_field="id", on_delete=models.CASCADE) diff --git a/apps/auth/tests.py b/apps/auth/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/apps/auth/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/auth/urls.py b/apps/auth/urls.py new file mode 100644 index 0000000..7d77a5f --- /dev/null +++ b/apps/auth/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from apps.auth import views + +urlpatterns = [ + path("gettoken/", views.gettoken, name="getToken"), + path("searchuser/", views.search_user, name="searchuser"), + path("adduser/", views.add_user, name="addUser"), + path("login/", views.login_user, name="loginUser"), +] diff --git a/apps/auth/views.py b/apps/auth/views.py new file mode 100644 index 0000000..1203c75 --- /dev/null +++ b/apps/auth/views.py @@ -0,0 +1,131 @@ +import binascii +import json, datetime +from django.shortcuts import HttpResponse +from django.middleware.csrf import get_token +from django.views.decorators.http import require_GET, require_POST +from apps.auth import models as auth_models +from django.contrib.auth.hashers import make_password, check_password +from apps.api.common import CaesarCypherClass, Base64CypherClass +from apps.api.config import Config + +# Create your views here. +config = Config() +base64 = Base64CypherClass() +caesar = CaesarCypherClass() + + +@require_GET +def gettoken(request): + """ + 获取token + :param request: + :return: + """ + token = get_token(request) + return HttpResponse(json.dumps({'token': token}), content_type="application/json,charset=utf-8") + + +@require_POST +def search_user(request): + """ + 查询用户名是否存在,若存在则返回True,不存在则返回False,如果使用加密版数据库则根据加密方式进行加密后再查询数据库 + :param request: + :return: + """ + if config.getconfig("isCypher"): # 启用加密数据库 + if config.getconfig("CypherMethod") == "caesar": # 加密方式为Caesar + username = caesar.caesar_encode(request.POST.get("username")) + user = auth_models.User.objects.using("cypher").filter(username=username) + else: # 加密方式为Base64 + username = base64.base64_encode_str(base64, request.POST.get("username")).decode('utf-8') + user = auth_models.User.objects.using("cypher").filter(username=username) + else: # 不加密的数据库 + username = request.POST.get("username") + user = auth_models.User.objects.using("default").filter(username=username) + if user.exists(): + return HttpResponse(True) + else: + return HttpResponse(False) + + +@require_POST +def add_user(request): + """ + 用户注册,前端需要将用户名密码以base64的方式加密后传输,存储密码时是用md5进行存储。 + 如果使用加密版数据库则根据加密方式,将用户名、邮箱、电话加密后存储到数据库。 + 用户头像目前以路径的方式存储 + :param request: POST提交注册信息 + :return: 注册结果 + """ + try: + create_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + last_login_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + avatar = request.FILES.get("avatar") + pwd_base64 = base64.base64_decode_str(base64, request.POST.get("pwd")) + pwd = make_password(pwd_base64) + if config.getconfig("isCypher"): # 启用加密数据库 + if config.getconfig("CypherMethod") == "caesar": # 加密方式为Caesar + username = caesar.caesar_encode(request.POST.get("username")) + email = caesar.caesar_encode(request.POST.get("email")) + phone = caesar.caesar_encode(request.POST.get("phone")) + else: # 加密方式为Base64 + username = base64.base64_encode_str(base64, request.POST.get("username")).decode('utf-8') + email = base64.base64_encode_str(base64, request.POST.get("email")).decode('utf-8') + phone = base64.base64_encode_str(base64, request.POST.get("phone")).decode('utf-8') + auth_models.User.objects.using("cypher").create( + username=username, + pwd=pwd, + email=email, + phone=phone, + create_time=create_time, + last_login_time=last_login_time, + avatar=avatar + ) + else: # 不加密的数据库 + username = request.POST.get("username") + email = request.POST.get("email") + phone = request.POST.get("phone") + auth_models.User.objects.using("default").create( + username=username, + pwd=pwd, + email=email, + phone=phone, + create_time=create_time, + last_login_time=last_login_time, + avatar=avatar + ) + return HttpResponse("添加用户成功") + except Exception as e: + return HttpResponse(f"报错了:{e}") + + +@require_POST +def login_user(request): + """ + 用户登录,验证用户密码是否正确,正确返回菜单,错误返回用户名或密码不正确。 + 如果使用加密版数据库则根据加密方式,将用户名加密后进行数据库查询。 + :param request: + :return: "用户名或密码不正确"或用户拥有权限的菜单 + """ + try: + pwd_input = base64.base64_decode_str(base64, request.POST.get("pwd")) + if config.getconfig("isCypher"): # 启用加密数据库 + if config.getconfig("CypherMethod") == "caesar": # 加密方式为Caesar + username = caesar.caesar_encode(request.POST.get("username")) + else: # 加密方式为Base64 + username = base64.base64_encode_str(base64, request.POST.get("username")).decode('utf-8') + pwd_made = auth_models.User.objects.using("cypher").filter(username=username).first() + else: # 不加密的数据库 + username = request.POST.get("username") + pwd_made = auth_models.User.objects.using("default").filter(username=username).first() + if pwd_made is not None: + if check_password(pwd_input, pwd_made.pwd): + return HttpResponse(True) + else: + return HttpResponse("用户名或密码不正确") + else: + return HttpResponse("用户名或密码不正确") + except binascii.Error as e: + return HttpResponse("base64解码失败") + except Exception as e: + return HttpResponse(f"报错了:{e}") diff --git a/apps/home/__init__.py b/apps/home/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/home/__pycache__/__init__.cpython-311.pyc b/apps/home/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..2989fa6 Binary files /dev/null and b/apps/home/__pycache__/__init__.cpython-311.pyc differ diff --git a/apps/home/__pycache__/apps.cpython-311.pyc b/apps/home/__pycache__/apps.cpython-311.pyc new file mode 100644 index 0000000..9592ac9 Binary files /dev/null and b/apps/home/__pycache__/apps.cpython-311.pyc differ diff --git a/apps/home/__pycache__/models.cpython-311.pyc b/apps/home/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000..e6c752b Binary files /dev/null and b/apps/home/__pycache__/models.cpython-311.pyc differ diff --git a/apps/home/__pycache__/views.cpython-311.pyc b/apps/home/__pycache__/views.cpython-311.pyc new file mode 100644 index 0000000..bfcdc70 Binary files /dev/null and b/apps/home/__pycache__/views.cpython-311.pyc differ diff --git a/apps/home/admin.py b/apps/home/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/apps/home/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/home/apps.py b/apps/home/apps.py new file mode 100644 index 0000000..c11732f --- /dev/null +++ b/apps/home/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class HomeConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.home' diff --git a/apps/home/migrations/__init__.py b/apps/home/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/home/migrations/__pycache__/__init__.cpython-311.pyc b/apps/home/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..490db15 Binary files /dev/null and b/apps/home/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/apps/home/models.py b/apps/home/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/apps/home/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/apps/home/tests.py b/apps/home/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/apps/home/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/home/views.py b/apps/home/views.py new file mode 100644 index 0000000..689d715 --- /dev/null +++ b/apps/home/views.py @@ -0,0 +1,20 @@ +from django.shortcuts import render, HttpResponse +from apps.api.common import CaesarCypherClass, Base64CypherClass + + +# Create your views here. +def home(request): + bs64 = Base64CypherClass() + s = request.GET.get('s') + print(s) + s_encode = bs64.base64_encode_str(bs64,s) + print(s_encode) + s_decode = bs64.base64_decode_str(bs64,s) + + # s_encode = bs64.base64_encode_pic(bs64, s) + # if s_encode != "图片路径不存在": + # s_decode = bs64.base64_decode_pic(bs64, s_encode) + # else: + # s_decode = '' + # return HttpResponse(f"解密:{s_decode}") + return HttpResponse(f"加密:{s_encode}\n解密:{s_decode}") diff --git a/data/db.sqlite3 b/data/db.sqlite3 new file mode 100644 index 0000000..4a836ea Binary files /dev/null and b/data/db.sqlite3 differ diff --git a/data/db_cypher.sqlite3 b/data/db_cypher.sqlite3 new file mode 100644 index 0000000..66149e3 Binary files /dev/null and b/data/db_cypher.sqlite3 differ diff --git a/data/initdata.json b/data/initdata.json new file mode 100644 index 0000000..216f09d --- /dev/null +++ b/data/initdata.json @@ -0,0 +1,16 @@ +[ + { + "model": "api.sysconfig", + "pk": 1, + "fields": { + "name": "系统名称", + "identity":"SysTitle", + "param":"图书管理系统", + "desc":"登录界面显示的系统标题", + "create_by":"admin", + "create_time":"2024-08-16 23:39:50", + "update_by":"admin", + "update_time":"2024-08-16 23:39:50" + } + } +] \ No newline at end of file diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..2c3670f --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CMS_Django_Backend.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/upload/avatar/default.jpg b/upload/avatar/default.jpg new file mode 100644 index 0000000..2f2a3a7 Binary files /dev/null and b/upload/avatar/default.jpg differ