最终实现:
首先需要在阿里云平台注册一个账号
注册好账号在输入框中搜索:
然后进入之后点击快速学习和测试,这一步其实不操作也可以
现在出来了资质管理,第一步就是要填这部分的内容
按需填写申请,一般是有俩小时审核期,所以可能要等半天时间才能搞的差不多
和上面同理填写内容申请:
截图属实麻烦,本来想写个从头到尾的操作的,实在不想搞,大家可以参考:
超详细阿里云平台操作
实现Django成功连接阿里云短信服务
实现代码的逻辑
1)前端form表单中输入电话号码后,点击发送,触发后端的发送验证码功能。
2)后端先解析电话号码是否合理,如果合理,则随机生成一个验证码,并使用阿里云的短信发送接口将验证码发送到该手机。并将手机号和验证码存到Mysql数据库中
3)前端用户收到短信后,在表单中填入验证码,点击登录按钮后触发后端的登录api。同时后端将收到的验证码,与Msql库中存的验证码进行比对,如果一致则合理,返回token及用户信息到前端。
创建utils_sms.py
-
安装阿里云 Python SDK
阿里云提供了一个 aliyun-python-sdk-core 包用于核心功能,以及一个 aliyun-python-sdk-dysmsapi 包用于短信服务。你可以使用以下命令来安装这两个包:pip install aliyun-python-sdk-core pip install aliyun-python-sdk-dysmsapi #utlis_sms.py from alibabacloud_dysmsapi20170525.client import Client as Dysmsapi20170525Client from alibabacloud_tea_openapi import models as open_api_models from alibabacloud_dysmsapi20170525 import models as dysmsapi_20170525_models from alibabacloud_tea_util import models as util_models def create_client(access_key_id, access_key_secret): config = open_api_models.Config( access_key_id=access_key_id, access_key_secret=access_key_secret ) config.endpoint = f'dysmsapi.aliyuncs.com' return Dysmsapi20170525Client(config) def send_sms(phone_number,code): client = create_client('your_access_key_id', 'your_access_key_secret') send_sms_request = dysmsapi_20170525_models.SendSmsRequest( sign_name='***', template_code='***', phone_numbers=phone_number, # template_param='{"code":"4567"}' template_param='{"code":"' + str(code) + '"}' ) runtime = util_models.RuntimeOptions() try: # 复制代码运行请自行打印 API 的返回值 response=client.send_sms_with_options(send_sms_request, runtime) return response except Exception as error: print(str(error)) return None
models.py
class VerificationCode(models.Model):
phone_number = models.CharField(max_length=15)
code = models.CharField(max_length=6)
created_at = models.DateTimeField(default=timezone.now)
def is_valid(self):
# 验证码有效期设置为5分钟
expiration_time = self.created_at + timedelta(minutes=5)
return timezone.now() <= expiration_time
不要忘记重新生成迁移文件
#python manage.py makemigrations
#python manage.py migrate
后端调用
def number_login(request):
return render(request,'number_login.html')
@csrf_exempt
def send_code(request):
if request.method == 'POST':
data = json.loads(request.body)
phone_number = data.get('phone_number')
# 有效电话号码
if not re.match(r'^\+?\d{10,15}$', phone_number):
return JsonResponse({'message': '无效的电话号码'}, status=400)
# 随机生成6位数的验证码
code = str(random.randint(100000, 999999))
#将手机号和验证码存到数据库的表中
VerificationCode.objects.create(phone_number=phone_number, code=code)
#通过阿里云给用户发短信
if send_sms(phone_number, code):
return JsonResponse({'message': '验证码发送成功'})
else:
return JsonResponse({'message': '验证码发送失败'}, status=500)
return JsonResponse({'message': '无效的请求方法'}, status=405)
@csrf_exempt
def verify_code(request):
if request.method == 'POST':
data = json.loads(request.body)
phone_number = data.get('phone_number')
code = data.get('code')
try:
#访问数据库查看手机号和验证码
verification = VerificationCode.objects.get(phone_number=phone_number, code=code)
if verification.is_valid():
#通过token进行验证前端的验证码和数据库中的验证码是否一致
# Generate a token (dummy example here)
token = 'example_token_12345'
return JsonResponse({'success': True, 'token': token})
else:
return JsonResponse({'success': False, 'message': '验证码已过期'}, status=400)
except VerificationCode.DoesNotExist:
return JsonResponse({'success': False, 'message': '无效的验证码'}, status=400)
return JsonResponse({'message': '无效的请求方法'}, status=405)
前端
number_login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>手机号验证码登录</title>
{% load static %}
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.css' %}">
<script src="{% static 'js/jquery-3.7.1.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.js' %}"></script>
<style>
body {
background-image: url("{% static 'img/your_background.png'%}");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
margin: 0;
padding: 0;
height: 100vh;
}
.c1 {
width: 500px;
height:500px;
border: 1px solid #dddddd;
border-radius: 5px;
margin: 200px auto;
padding: 40px 40px;
box-shadow: 5px 5px 5px #aaa;
background-color: white;
}
此处有省略css,可以根据自己喜欢的调整页面布局
</style>
</head>
<body>
<div class="c1">
<div class="ant-tabs-nav-list">
<div class="ant-tabs-tab ant-tabs-tab-active">
<div role="tab" aria-selected="true" class="ant-tabs-tab-btn" tabindex="0" id="rc-tabs-0-tab-code-login" aria-controls="rc-tabs-0-panel-code-login">
<a href="/user/login/">密码登录</a>
</div>
</div>
<div class="ant-tabs-tab">
<div role="tab" aria-selected="false" class="ant-tabs-tab-btn" tabindex="0" id="rc-tabs-0-tab-number-login" aria-controls="rc-tabs-0-panel-number-login">
<a href="/number/login/">手机号登录</a>
</div>
</div>
</div>
<form id="verification-form">
<div class="form-group">
<label for="phone-number">手机号</label>
<input type="text" id="phone-number" class="form-control" placeholder="请输入手机号" required>
</div>
<button type="button" onclick="sendCode()" class="btn btn-primary">发送验证码</button>
</form>
<form id="code-form" style="margin-top: 20px;">
<div class="form-group">
<label for="code">验证码</label>
<input type="text" id="code" class="form-control" placeholder="请输入验证码" required>
</div>
<button type="button" onclick="verifyCode()" class="btn btn-primary">登录</button>
</form>
</div>
<script>
async function sendCode() {
const phoneNumber = document.getElementById('phone-number').value;
const response = await fetch('/send_code/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCsrfToken()
},
body: JSON.stringify({ phone_number: phoneNumber })
});
const data = await response.json();
alert(data.message);
}
async function verifyCode() {
const phoneNumber = document.getElementById('phone-number').value;
const code = document.getElementById('code').value;
const response = await fetch('/verify_code/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCsrfToken()
},
body: JSON.stringify({ phone_number: phoneNumber, code: code })
});
const data = await response.json();
if (data.success) {
window.location.href = '/index/';
} else {
alert('Verification failed: ' + data.message);
}
}
function getCsrfToken() {
let csrfToken = null;
const cookies = document.cookie.split(';');
cookies.forEach(cookie => {
const [name, value] = cookie.split('=');
if (name.trim() === 'csrftoken') {
csrfToken = value;
}
});
return csrfToken;
}
</script>
</body>
</html>
总结
每个人写代码的习惯都不一样,但是整体的思路应该是一样的,强烈建议思考我写的实现代码逻辑那部分内容,然后以代码为辅,帮助小伙伴们解决难题。如果看这篇文章有难以让你理解的地方,请留言评论,最近比较活跃,我看到的话会及时回复。