__init__.py
import pymysql
pymysql.install_as_MySQLdb()
setting.py
# Mysql
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'xuanjian', # 数据库名
'USER': 'xuanjian_root', # 账号
'PASSWORD': '', # 密码
'HOST': '127.0.0.1', # HOST
'POST': 3306, # 端口
'OPTIONS': {
'init_command': 'SET sql_mode="STRICT_TRANS_TABLES"',
'charset': 'utf8mb4'
}
}
}
# drf配置
REST_FRAMEWORK = {
# 全局使用的认证类
"DEFAULT_AUTHENTICATION_CLASSES": [
'yourapp.auth.MyAuth',
'yourapp.auth.PasswordAuth',
],
'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S',
'EXCEPTION_HANDLER': 'yourapp.exception.exception_handler', # 全局配置异常模块
'DEFAULT_RENDERER_CLASSES': (
'yourapp.render.CustomRenderer', # 设置自定义返回数据格式
),
}
# 更改MyUser为用户表
AUTH_USER_MODEL = 'yourapp.Users'
# sm4加密key
SM4_KEY = "KGc3zITWUAzcxQa4"
# 自定义加密方式
PASSWORD_HASHERS = (
'yourapp.hashers.SM4PasswordHasher',
)
# 配置 MEDIA_ROOT 作为你上传文件在服务器中的基本路径
MEDIA_ROOT = os.path.join(BASE_DIR, 'upload') # 注意此处不要写成列表或元组的形式
# 配置 MEDIA_URL 作为公用 URL,指向上传文件的基本路径
MEDIA_URL = '/media/'
# 这里特意写成 upload 和 media,而不是统一写成 media 或 upload,是为了便于理解 MEDIA_ROOT 和 MEDIA_URL 的作用和区别
# 自定义账号密码认证
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'yourapp.auth.PasswordAuth'
]
urls.py
urlpatterns = [
path('', include('yourapp.urls')),
url(r'media/(?P.*)$', serve, {'document_root': settings.MEDIA_ROOT})
]
yourapp/auth.py
import datetime
from django.contrib.auth.backends import ModelBackend
from rest_framework import exceptions
from xuanjian.models import Users, Tokens
from xuanjian.sm4 import SM4EncryptDecrypt
# 全局加密解密对象
sm4 = SM4EncryptDecrypt()
class MyAuth:
def authenticate(self, request):
# 该示例认证是需要在请求的url加上参数token(实际直接是校验用户名或密码或者登陆标识等)
token = request.headers.get('Token')
token_obj = Tokens.objects.filter(token=token).first()
if not token_obj:
raise exceptions.AuthenticationFailed('未认证用户!')
elif token_obj.valid_time < datetime.datetime.utcnow():
token_obj.delete()
raise exceptions.AuthenticationFailed('认证失效!')
else:
user_obj = token_obj.user_set.all().first()
if not user_obj.is_active:
raise exceptions.AuthenticationFailed('账户已冻结!')
else:
return user_obj, 'request.auth' # 认证函数执行结果如果通过则为元组,元组第一个元素封装在为request.user,第二个元素封装为request.auth
def authenticate_header(self, request):
pass
class PasswordAuth(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
if username and password:
user = Users.objects.filter(username=username, password=sm4.encrypt(password), is_active=True)
if user:
return user.first()
return None
yourapp/exception.py
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response
from rest_framework import status
def exception_handler(exc, context):
response = drf_exception_handler(exc, context)
print(exc, context)
if not response: # 服务端错误
response = Response({'detail': '服务器内部错误,{}:{}'.format(context['view'], exc)},
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return response
yourapp/hashers.py
from django.contrib.auth.hashers import BasePasswordHasher
from xuanjian.sm4 import SM4EncryptDecrypt
class SM4PasswordHasher(BasePasswordHasher):
algorithm = "mymd5"
# 全局加密解密对象
sm4 = SM4EncryptDecrypt()
def encode(self, password, salt):
assert password is not None
return self.sm4.encrypt(password)
def verify(self, password, encoded):
encoded_2 = self.sm4.encrypt(password)
return encoded == encoded_2
def decode(self, encoded):
return self.sm4.decrypt(encoded)
def safe_summary(self, encoded):
return {'algorithm': self.algorithm, 'salt': '', 'hash': ''}
yourapp/models.py
from datetime import datetime
from django.contrib.auth.models import AbstractUser, Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.db import models
# Create your models here.
# 文件上传,名字自定义
def custom_upload_path(instance, filename):
folder = instance.__class__.__name__.lower()
date_str = "%s%02d%02d%02d%02d%02d" % (datetime.now().year, datetime.now().month, datetime.now().day,
datetime.now().hour, datetime.now().minute, datetime.now().second)
filename = filename.split('.')[0] + '_' + date_str + "." + filename.split('.')[-1]
return "{}/{}".format(folder, filename)
# 用户模型
class Users(AbstractUser):
"""
用户表,继承于默认用户表
"""
sex = models.BooleanField(default=True, verbose_name='性别')
birthday = models.DateField(blank=True, null=True, verbose_name='生日')
phone = models.CharField(max_length=11, null=True, verbose_name='联系方式')
image = models.ImageField(upload_to=custom_upload_path, null=True, verbose_name='头像')
token = models.ForeignKey('Tokens', on_delete=models.SET_NULL, null=True, related_name="user_set",
related_query_name="user", verbose_name='用户Token')
update_time = models.DateTimeField(help_text='修改时间', auto_now=True)
class Meta:
db_table = 'users'
yourapp/render.py
from rest_framework.renderers import JSONRenderer
class CustomRenderer(JSONRenderer):
# 重构render方法
def render(self, data, accepted_media_type=None, renderer_context=None):
if not data.get('code', None):
data = {
'code': 500,
'message': '服务器错误',
'result': data
}
return super().render(data, accepted_media_type, renderer_context)
sm4.py
from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT
import binascii
from xuanjian_python.settings import SM4_KEY
class SM4EncryptDecrypt:
"""
国密sm4加解密
"""
def __init__(self):
self.encrypt_key = SM4_KEY
self.decrypt_key = SM4_KEY
self.crypt_sm4 = CryptSM4()
def str_to_hexStr(self, hex_str):
"""
字符串转hex
:param hex_str: 字符串
:return: hex
"""
hex_data = hex_str.encode('utf-8')
str_bin = binascii.unhexlify(hex_data)
return str_bin.decode('utf-8')
def encrypt(self, value):
"""
国密sm4加密
# :param encrypt_key: sm4加密key
:param value: 待加密的字符串
:return: sm4加密后的hex值
"""
crypt_sm4 = self.crypt_sm4
crypt_sm4.set_key(self.encrypt_key.encode(), SM4_ENCRYPT)
encrypt_value = crypt_sm4.crypt_ecb(value.encode()) # bytes类型
return encrypt_value.hex()
def decrypt(self, encrypt_value):
"""
国密sm4解密
# :param decrypt_key:sm4加密key
:param encrypt_value: 待解密的hex值
:return: 原字符串
"""
crypt_sm4 = self.crypt_sm4
crypt_sm4.set_key(self.decrypt_key.encode(), SM4_DECRYPT)
decrypt_value = crypt_sm4.crypt_ecb(bytes.fromhex(encrypt_value)) # bytes类型
return self.str_to_hexStr(decrypt_value.hex())
if __name__ == '__main__':
# str_data = {"ffffffwsdwefewd": "fefefewfwrv", "qazqaz": "vfbfrbgtrnujy"}
str_data = '123456789'
SM4 = SM4EncryptDecrypt()
print("待加密内容:", str_data)
encoding = SM4.encrypt(str(str_data))
print("国密sm4加密后的结果:", encoding)
print("国密sm4解密后的结果:", SM4.decrypt('f8943bcda25190019cbcbadabdbaf3c7'))