perf: 优化短信 (#6826)

* perf: 优化短信

* refactor: 适配新的短信模板配置

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: xinwen <coderWen@126.com>
pull/6835/head
fit2bot 2021-09-13 20:15:59 +08:00 committed by GitHub
parent 55a5dd1e34
commit 7a45f4d129
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 58 additions and 81 deletions

View File

@ -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))

View File

@ -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):

View File

@ -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):

View File

@ -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',

View File

@ -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

View File

@ -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.

View File

@ -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"

View File

@ -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')})

View File

@ -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')})

View File

@ -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'))

View File

@ -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')
)