mirror of https://github.com/jumpserver/jumpserver
perf: 优化短信 (#6826)
* perf: 优化短信 * refactor: 适配新的短信模板配置 Co-authored-by: ibuler <ibuler@qq.com> Co-authored-by: xinwen <coderWen@126.com>pull/6835/head
parent
55a5dd1e34
commit
7a45f4d129
|
@ -11,34 +11,6 @@ from common.exceptions import JMSException
|
|||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
class SMS_MESSAGE(TextChoices):
|
||||
"""
|
||||
定义短信的各种消息类型,会存到类似 `ALIBABA_SMS_SIGN_AND_TEMPLATES` settings 里
|
||||
|
||||
{
|
||||
'verification_code': {'sign_name': 'Jumpserver', 'template_code': 'SMS_222870834'},
|
||||
...
|
||||
}
|
||||
"""
|
||||
|
||||
"""
|
||||
验证码签名和模板。模板例子:
|
||||
`您的验证码:${code},您正进行身份验证,打死不告诉别人!`
|
||||
其中必须包含 `code` 变量
|
||||
"""
|
||||
VERIFICATION_CODE = 'verification_code'
|
||||
|
||||
def get_sign_and_tmpl(self, config: dict):
|
||||
try:
|
||||
data = config[self]
|
||||
return data['sign_name'], data['template_code']
|
||||
except KeyError as e:
|
||||
raise JMSException(
|
||||
code=f'{settings.SMS_BACKEND}_sign_and_tmpl_bad',
|
||||
detail=_('Invalid SMS sign and template: {}').format(e)
|
||||
)
|
||||
|
||||
|
||||
class BACKENDS(TextChoices):
|
||||
ALIBABA = 'alibaba', _('Alibaba cloud')
|
||||
TENCENT = 'tencent', _('Tencent cloud')
|
||||
|
@ -49,11 +21,7 @@ class BaseSMSClient:
|
|||
短信终端的基类
|
||||
"""
|
||||
|
||||
SIGN_AND_TMPL_SETTING_FIELD: str
|
||||
|
||||
@property
|
||||
def sign_and_tmpl(self):
|
||||
return getattr(settings, self.SIGN_AND_TMPL_SETTING_FIELD, {})
|
||||
SIGN_AND_TMPL_SETTING_FIELD_PREFIX: str
|
||||
|
||||
@classmethod
|
||||
def new_from_settings(cls):
|
||||
|
@ -86,5 +54,12 @@ class SMS:
|
|||
)
|
||||
|
||||
def send_verify_code(self, phone_number, code):
|
||||
sign_name, template_code = SMS_MESSAGE.VERIFICATION_CODE.get_sign_and_tmpl(self.client.sign_and_tmpl)
|
||||
sign_name = getattr(settings, f'{self.client.SIGN_AND_TMPL_SETTING_FIELD_PREFIX}_VERIFY_SIGN_NAME')
|
||||
template_code = getattr(settings, f'{self.client.SIGN_AND_TMPL_SETTING_FIELD_PREFIX}_VERIFY_TEMPLATE_CODE')
|
||||
|
||||
if not (sign_name and template_code):
|
||||
raise JMSException(
|
||||
code='verify_code_sign_tmpl_invalid',
|
||||
detail=_('SMS verification code signature or template invalid')
|
||||
)
|
||||
return self.send_sms([phone_number], sign_name, template_code, OrderedDict(code=code))
|
||||
|
|
|
@ -15,7 +15,7 @@ logger = get_logger(__file__)
|
|||
|
||||
|
||||
class AlibabaSMS(BaseSMSClient):
|
||||
SIGN_AND_TMPL_SETTING_FIELD = 'ALIBABA_SMS_SIGN_AND_TEMPLATES'
|
||||
SIGN_AND_TMPL_SETTING_FIELD_PREFIX = 'ALIBABA'
|
||||
|
||||
@classmethod
|
||||
def new_from_settings(cls):
|
||||
|
|
|
@ -20,7 +20,7 @@ class TencentSMS(BaseSMSClient):
|
|||
"""
|
||||
https://cloud.tencent.com/document/product/382/43196#.E5.8F.91.E9.80.81.E7.9F.AD.E4.BF.A1
|
||||
"""
|
||||
SIGN_AND_TMPL_SETTING_FIELD = 'TENCENT_SMS_SIGN_AND_TEMPLATES'
|
||||
SIGN_AND_TMPL_SETTING_FIELD_PREFIX = 'TENCENT'
|
||||
|
||||
@classmethod
|
||||
def new_from_settings(cls):
|
||||
|
|
|
@ -249,12 +249,14 @@ class Config(dict):
|
|||
|
||||
'ALIBABA_ACCESS_KEY_ID': '',
|
||||
'ALIBABA_ACCESS_KEY_SECRET': '',
|
||||
'ALIBABA_SMS_SIGN_AND_TEMPLATES': {},
|
||||
'ALIBABA_VERIFY_SIGN_NAME': '',
|
||||
'ALIBABA_VERIFY_TEMPLATE_CODE': '',
|
||||
|
||||
'TENCENT_SECRET_ID': '',
|
||||
'TENCENT_SECRET_KEY': '',
|
||||
'TENCENT_SDKAPPID': '',
|
||||
'TENCENT_SMS_SIGN_AND_TEMPLATES': {},
|
||||
'TENCENT_VERIFY_SIGN_NAME': '',
|
||||
'TENCENT_VERIFY_TEMPLATE_CODE': '',
|
||||
|
||||
'OTP_VALID_WINDOW': 2,
|
||||
'OTP_ISSUER_NAME': 'JumpServer',
|
||||
|
|
|
@ -122,21 +122,7 @@ AUTH_FEISHU = CONFIG.AUTH_FEISHU
|
|||
FEISHU_APP_ID = CONFIG.FEISHU_APP_ID
|
||||
FEISHU_APP_SECRET = CONFIG.FEISHU_APP_SECRET
|
||||
|
||||
# SMS auth
|
||||
SMS_ENABLED = CONFIG.SMS_ENABLED
|
||||
SMS_BACKEND = CONFIG.SMS_BACKEND
|
||||
SMS_TEST_PHONE = CONFIG.SMS_TEST_PHONE
|
||||
|
||||
# Alibaba
|
||||
ALIBABA_ACCESS_KEY_ID = CONFIG.ALIBABA_ACCESS_KEY_ID
|
||||
ALIBABA_ACCESS_KEY_SECRET = CONFIG.ALIBABA_ACCESS_KEY_SECRET
|
||||
ALIBABA_SMS_SIGN_AND_TEMPLATES = CONFIG.ALIBABA_SMS_SIGN_AND_TEMPLATES
|
||||
|
||||
# TENCENT
|
||||
TENCENT_SECRET_ID = CONFIG.TENCENT_SECRET_ID
|
||||
TENCENT_SECRET_KEY = CONFIG.TENCENT_SECRET_KEY
|
||||
TENCENT_SDKAPPID = CONFIG.TENCENT_SDKAPPID
|
||||
TENCENT_SMS_SIGN_AND_TEMPLATES = CONFIG.TENCENT_SMS_SIGN_AND_TEMPLATES
|
||||
|
||||
# Other setting
|
||||
TOKEN_EXPIRATION = CONFIG.TOKEN_EXPIRATION
|
||||
|
|
|
@ -132,3 +132,20 @@ LOGIN_REDIRECT_MSG_ENABLED = CONFIG.LOGIN_REDIRECT_MSG_ENABLED
|
|||
CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS = CONFIG.CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS
|
||||
|
||||
XRDP_ENABLED = CONFIG.XRDP_ENABLED
|
||||
|
||||
|
||||
# SMS enabled
|
||||
SMS_ENABLED = CONFIG.SMS_ENABLED
|
||||
SMS_BACKEND = CONFIG.SMS_BACKEND
|
||||
SMS_TEST_PHONE = CONFIG.SMS_TEST_PHONE
|
||||
|
||||
# Alibaba
|
||||
ALIBABA_ACCESS_KEY_ID = CONFIG.ALIBABA_ACCESS_KEY_ID
|
||||
ALIBABA_ACCESS_KEY_SECRET = CONFIG.ALIBABA_ACCESS_KEY_SECRET
|
||||
ALIBABA_SMS_SIGN_AND_TEMPLATES = CONFIG.ALIBABA_SMS_SIGN_AND_TEMPLATES
|
||||
|
||||
# TENCENT
|
||||
TENCENT_SECRET_ID = CONFIG.TENCENT_SECRET_ID
|
||||
TENCENT_SECRET_KEY = CONFIG.TENCENT_SECRET_KEY
|
||||
TENCENT_SDKAPPID = CONFIG.TENCENT_SDKAPPID
|
||||
TENCENT_SMS_SIGN_AND_TEMPLATES = CONFIG.TENCENT_SMS_SIGN_AND_TEMPLATES
|
||||
|
|
Binary file not shown.
|
@ -2789,7 +2789,7 @@ msgstr "短信服务商"
|
|||
|
||||
#: settings/serializers/auth/sms.py:15 settings/serializers/email.py:69
|
||||
msgid "Signature"
|
||||
msgstr "署名"
|
||||
msgstr "签名"
|
||||
|
||||
#: settings/serializers/auth/sms.py:16
|
||||
msgid "Template"
|
||||
|
|
|
@ -4,7 +4,6 @@ from rest_framework.exceptions import APIException
|
|||
from rest_framework import status
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from common.message.backends.sms import SMS_MESSAGE
|
||||
from common.message.backends.sms.alibaba import AlibabaSMS
|
||||
from settings.models import Setting
|
||||
from common.permissions import IsSuperUser
|
||||
|
@ -23,7 +22,8 @@ class AlibabaSMSTestingAPI(GenericAPIView):
|
|||
|
||||
alibaba_access_key_id = serializer.validated_data['ALIBABA_ACCESS_KEY_ID']
|
||||
alibaba_access_key_secret = serializer.validated_data.get('ALIBABA_ACCESS_KEY_SECRET')
|
||||
alibaba_sms_sign_and_tmpl = serializer.validated_data['ALIBABA_SMS_SIGN_AND_TEMPLATES']
|
||||
alibaba_verify_sign_name = serializer.validated_data['ALIBABA_VERIFY_SIGN_NAME']
|
||||
alibaba_verify_template_code = serializer.validated_data['ALIBABA_VERIFY_TEMPLATE_CODE']
|
||||
test_phone = serializer.validated_data.get('SMS_TEST_PHONE')
|
||||
|
||||
if not test_phone:
|
||||
|
@ -41,12 +41,11 @@ class AlibabaSMSTestingAPI(GenericAPIView):
|
|||
access_key_id=alibaba_access_key_id,
|
||||
access_key_secret=alibaba_access_key_secret
|
||||
)
|
||||
sign, tmpl = SMS_MESSAGE.VERIFICATION_CODE.get_sign_and_tmpl(alibaba_sms_sign_and_tmpl)
|
||||
|
||||
client.send_sms(
|
||||
phone_numbers=[test_phone],
|
||||
sign_name=sign,
|
||||
template_code=tmpl,
|
||||
sign_name=alibaba_verify_sign_name,
|
||||
template_code=alibaba_verify_template_code,
|
||||
template_param={'code': 'test'}
|
||||
)
|
||||
return Response(status=status.HTTP_200_OK, data={'msg': _('Test success')})
|
||||
|
|
|
@ -6,7 +6,6 @@ from rest_framework.exceptions import APIException
|
|||
from rest_framework import status
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from common.message.backends.sms import SMS_MESSAGE
|
||||
from common.message.backends.sms.tencent import TencentSMS
|
||||
from settings.models import Setting
|
||||
from common.permissions import IsSuperUser
|
||||
|
@ -25,7 +24,8 @@ class TencentSMSTestingAPI(GenericAPIView):
|
|||
|
||||
tencent_secret_id = serializer.validated_data['TENCENT_SECRET_ID']
|
||||
tencent_secret_key = serializer.validated_data.get('TENCENT_SECRET_KEY')
|
||||
tencent_sms_sign_and_tmpl = serializer.validated_data['TENCENT_SMS_SIGN_AND_TEMPLATES']
|
||||
tencent_verify_sign_name = serializer.validated_data['TENCENT_VERIFY_SIGN_NAME']
|
||||
tencent_verify_template_code = serializer.validated_data['TENCENT_VERIFY_TEMPLATE_CODE']
|
||||
tencent_sdkappid = serializer.validated_data.get('TENCENT_SDKAPPID')
|
||||
|
||||
test_phone = serializer.validated_data.get('SMS_TEST_PHONE')
|
||||
|
@ -46,12 +46,11 @@ class TencentSMSTestingAPI(GenericAPIView):
|
|||
secret_key=tencent_secret_key,
|
||||
sdkappid=tencent_sdkappid
|
||||
)
|
||||
sign, tmpl = SMS_MESSAGE.VERIFICATION_CODE.get_sign_and_tmpl(tencent_sms_sign_and_tmpl)
|
||||
|
||||
client.send_sms(
|
||||
phone_numbers=[test_phone],
|
||||
sign_name=sign,
|
||||
template_code=tmpl,
|
||||
sign_name=tencent_verify_sign_name,
|
||||
template_code=tencent_verify_template_code,
|
||||
template_param=OrderedDict(code='test')
|
||||
)
|
||||
return Response(status=status.HTTP_200_OK, data={'msg': _('Test success')})
|
||||
|
|
|
@ -8,12 +8,14 @@ __all__ = ['SMSSettingSerializer', 'AlibabaSMSSettingSerializer', 'TencentSMSSet
|
|||
|
||||
class SMSSettingSerializer(serializers.Serializer):
|
||||
SMS_ENABLED = serializers.BooleanField(default=False, label=_('Enable SMS'))
|
||||
SMS_BACKEND = serializers.ChoiceField(choices=BACKENDS.choices, default=BACKENDS.ALIBABA, label=_('SMS provider'))
|
||||
SMS_BACKEND = serializers.ChoiceField(
|
||||
choices=BACKENDS.choices, default=BACKENDS.ALIBABA, label=_('SMS provider')
|
||||
)
|
||||
|
||||
|
||||
class SignAndTmplPairSerializer(serializers.Serializer):
|
||||
sign_name = serializers.CharField(max_length=256, required=True, label=_('Signature'))
|
||||
template_code = serializers.CharField(max_length=256, required=True, label=_('Template'))
|
||||
class SignTmplPairSerializer(serializers.Serializer):
|
||||
SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature'))
|
||||
TEMPLATE_CODE = serializers.CharField(max_length=256, required=True, label=_('Template code'))
|
||||
|
||||
|
||||
class BaseSMSSettingSerializer(serializers.Serializer):
|
||||
|
@ -25,23 +27,18 @@ class BaseSMSSettingSerializer(serializers.Serializer):
|
|||
return data
|
||||
|
||||
|
||||
class SignAndTmplSerializer(serializers.Serializer):
|
||||
verification_code = SignAndTmplPairSerializer(default={'sign_name': '', 'template_code': ''})
|
||||
|
||||
|
||||
class AlibabaSMSSettingSerializer(BaseSMSSettingSerializer):
|
||||
ALIBABA_ACCESS_KEY_ID = serializers.CharField(max_length=256, required=True, label='AccessKeyId')
|
||||
ALIBABA_ACCESS_KEY_SECRET = serializers.CharField(
|
||||
max_length=256, required=False, label='AccessKeySecret', write_only=True)
|
||||
ALIBABA_SMS_SIGN_AND_TEMPLATES = SignAndTmplSerializer(
|
||||
label=_('Signatures and Templates'), required=True
|
||||
max_length=256, required=False, label='AccessKeySecret', write_only=True
|
||||
)
|
||||
ALIBABA_VERIFY_SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature'))
|
||||
ALIBABA_VERIFY_TEMPLATE_CODE = serializers.CharField(max_length=256, required=True, label=_('Template code'))
|
||||
|
||||
|
||||
class TencentSMSSettingSerializer(BaseSMSSettingSerializer):
|
||||
TENCENT_SECRET_ID = serializers.CharField(max_length=256, required=True, label='Secret id')
|
||||
TENCENT_SECRET_KEY = serializers.CharField(max_length=256, required=False, label='Secret key', write_only=True)
|
||||
TENCENT_SDKAPPID = serializers.CharField(max_length=256, required=True, label='SDK app id')
|
||||
TENCENT_SMS_SIGN_AND_TEMPLATES = SignAndTmplSerializer(
|
||||
label=_('Signatures and Templates'), required=True
|
||||
)
|
||||
TENCENT_VERIFY_SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature'))
|
||||
TENCENT_VERIFY_TEMPLATE_CODE = serializers.CharField(max_length=256, required=True, label=_('Template code'))
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from abc import ABCMeta
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
|
@ -17,8 +15,12 @@ class OtherSettingSerializer(serializers.Serializer):
|
|||
OTP_VALID_WINDOW = serializers.IntegerField(label=_("OTP valid window"))
|
||||
|
||||
PERIOD_TASK_ENABLED = serializers.BooleanField(required=False, label=_("Enable period task"))
|
||||
WINDOWS_SSH_DEFAULT_SHELL = serializers.CharField(
|
||||
required=False, max_length=1024, label=_('Ansible windows default shell'),
|
||||
WINDOWS_SSH_DEFAULT_SHELL = serializers.ChoiceField(
|
||||
choices=[
|
||||
('cmd', _("CMD")),
|
||||
('powershell', _("PowerShell"))
|
||||
],
|
||||
label=_('Ansible windows default shell'),
|
||||
help_text=_('The shell type used when Windows assets perform ansible tasks')
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in New Issue