实现思路

前端(Flutter应用)的工作:

  1. 收集用户信息

    • 用户输入手机号码,前端收集这个信息。
  2. 发送请求到后端

    • 当用户点击发送验证码按钮时,前端向后端发送一个包含手机号码的请求。
  3. 接收后端响应

    • 根据后端的响应,前端显示相应的信息给用户,比如“验证码发送成功”或“发送失败”。
  4. 收集验证码输入

    • 用户收到短信后,将验证码输入到前端界面。
  5. 提交验证码进行验证

    • 用户提交验证码后,前端将手机号码和验证码一起发送到后端进行验证。

后端的工作:

  1. 接收来自前端的请求

    • 后端接收来自前端的包含手机号码的请求。
  2. 生成验证码

    • 后端生成一个随机的验证码。
  3. 调用短信服务API发送验证码

    • 后端调用阿里云短信服务API,将验证码发送到用户的手机号码。
  4. 存储验证码

    • 后端暂时存储验证码及其相关信息(如手机号、过期时间等),以便稍后验证。
  5. 响应前端

    • 后端向前端发送响应,表示验证码是否发送成功。
  6. 接收并验证验证码

    • 当用户提交验证码时,后端接收手机号码和验证码,验证验证码的正确性。
  7. 返回验证结果

    • 后端返回验证结果给前端,如“验证成功”或“验证失败”。

前期准备工作

我使用的是阿里云短信服务,在调用短信API之前,要完成以下工作:

  1. 申请产品试用

image.png 2. 定义模板和签名

  • 短信服务中心完成模板和签名的申请。模板和签名定义了你收到短信的内容,这一步可以不进行,阿里云提供了专用的测试模板和签名,可以直接使用

Pasted image 20231225125049.png 3. 添加测试手机号

Pasted image 20231225125415.png 4. 获取AccessKey ID 和 AccessKey Secret

  • 点击右上角头像,点击AccessKey管理,点击创建AccessKey按钮,创建新的AccessKey,记得保存好AccessKey ID 和 AccessKey Secret

Pasted image 20231225125956.png

前端代码

界面代码

class Sms extends StatefulWidget {  
const Sms({super.key});  
  
@override  
State<Sms> createState() => _SmsState();  
}  
  
class _SmsState extends State<Sms> {  
final TextEditingController _phoneController = TextEditingController();  
final TextEditingController _codeController = TextEditingController();  
bool _isButtonDisabled = true;  
bool _isCodeSent = false;  
int _countdown = 60;  
  
final SmsController _smsController = SmsController();  
  
void _updateState() {  
setState(() {  
_isCodeSent = true;  
_startCountdown();  
});  
}  
  
void _startCountdown() {  
Future.delayed(Duration(seconds: 1), () {  
if (_countdown > 0) {  
setState(() {  
_countdown--;  
});  
_startCountdown();  
} else {  
setState(() {  
_isCodeSent = false;  
_countdown = 60;  
});  
}  
});  
}  
  
@override  
Widget build(BuildContext context) {  
return Scaffold(  
appBar: AppBar(title: Text('验证码登录')),  
body: Padding(  
padding: EdgeInsets.all(16.0),  
child: Column(  
mainAxisAlignment: MainAxisAlignment.center,  
crossAxisAlignment: CrossAxisAlignment.stretch,  
children: <Widget>[  
Text(  
'使用验证码登录',  
textAlign: TextAlign.center,  
style: TextStyle(fontSize: MediaQuery.of(context).size.width * 0.05),  
),  
SizedBox(height: 20),  
Row(  
children: <Widget>[  
Expanded(  
child: TextField(  
controller: _phoneController,  
decoration: InputDecoration(hintText: '输入手机号'),  
keyboardType: TextInputType.phone,  
),  
),  
TextButton(  
child: _isCodeSent  
? Text('重发($_countdown)')  
: Text('发送验证码'),  
onPressed: _isCodeSent ? null : () async {  
await _smsController.sendCode(  
_phoneController.text, context, _updateState);  
},  
),  
],  
),  
TextField(  
controller: _codeController,  
decoration: InputDecoration(hintText: '输入验证码'),  
onChanged: (value) {  
setState(() {  
_isButtonDisabled = value.isEmpty;  
});  
},  
),  
SizedBox(height: 20),  
ElevatedButton(  
child: Text('登录'),  
onPressed: _isButtonDisabled ? null : () async {  
await _smsController.verifyCodeAndLogin(  
_phoneController.text, _codeController.text, context);  
},  
),  
],  
),  
),  
);  
}  
}

在界面这部分我引用了smsController类中的两个方法,在这两个方法中我调用后端接口,分别实现了发送验证码,以及验证验证码的功能。代码如下:

class SmsController {  
Future<void> verifyCodeAndLogin(String phoneNumber, String code, BuildContext context) async {  
final response = await http.post(  
//后端接口,替换你的后端接口
Uri.parse('http://000.000.0000.000/verify_code'),  
headers: <String, String>{  
'Content-Type': 'application/json',  
},  
body: jsonEncode(<String, String>{  
'phone_number': phoneNumber,  
'code': code,  
}),  
);  
  
if (response.statusCode == 200) {  
Navigator.pushNamed(context, '/index');  
} else {  
ScaffoldMessenger.of(context).showSnackBar(  
SnackBar(content: Text('手机号或验证码错误')),  
);  
}  
}  
  
Future<void> sendCode(String phoneNumber, BuildContext context, Function updateState) async {  
if (phoneNumber.length == 11) {  
final response = await http.post(
//后端接口,替换你的后端接口
Uri.parse('http://000.000.0000.000/send_verification_sms'),  
headers: <String, String>{  
'Content-Type': 'application/json',  
},  
body: jsonEncode(<String, String>{  
'phone_number': phoneNumber,  
}),  
);  
  
if (response.statusCode == 200) {  
updateState();  
ScaffoldMessenger.of(context).showSnackBar(  
SnackBar(content: Text('验证码已成功发送')),  
);  
} else {  
ScaffoldMessenger.of(context).showSnackBar(  
SnackBar(content: Text('验证码发送失败')),  
);  
}  
} else {  
ScaffoldMessenger.of(context).showSnackBar(  
SnackBar(content: Text('手机号格式错误')),  
);  
}  
}  
}

后端代码使用python实现,代码如下

@app.route('/send_verification_sms', methods=['POST'])
async def send_verification_sms():
    phone_number = (await request.get_json()).get('phone_number')
    if not phone_number:
        return jsonify({"error": "Phone number is required"}), 400

    sign_name = "阿里云短信测试"  # Replace with your sign name
    #输入你的模板code
    template_code = "" 
    try:
        response = send_sms(phone_number, sign_name, template_code)
        return jsonify({"message": "SMS sent successfully", "response": str(response)})
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@app.route('/verify_code', methods=['POST'])
async def verify_sms_code():
    json_data = await request.get_json()
    phone_number = json_data.get('phone_number')
    code = json_data.get('code')

    if verify_code(phone_number, code):
        return jsonify({"message": "Verification successful"})
    else:
        return jsonify({"error": "Invalid or expired code"}), 400

#输入你的ACCESS_KEY_ID和ACCESS_KEY_SECRET
ACCESS_KEY_ID = ""
ACCESS_KEY_SECRET = ""
client = AcsClient(ACCESS_KEY_ID, ACCESS_KEY_SECRET, 'cn-hangzhou')

def send_sms(phone_numbers, sign_name, template_code):
    request = CommonRequest()
    request.set_accept_format('json')
    request.set_domain('dysmsapi.aliyuncs.com')
    request.set_method('POST')
    request.set_protocol_type('https')  # https | http
    request.set_version('2017-05-25')
    request.set_action_name('SendSms')

    request.add_query_param('RegionId', "cn-hangzhou")
    request.add_query_param('PhoneNumbers', phone_numbers)
    request.add_query_param('SignName', sign_name)
    request.add_query_param('TemplateCode', template_code)

    verification_code = generate_verification_code()
    params = f"{{\"code\":\"{verification_code}\"}}"
    request.add_query_param('TemplateParam', params)

    # 保存验证码和时间戳
    with shelve.open('verification_codes.db') as db:
        db[phone_numbers] = {'code': verification_code, 'timestamp': datetime.now()}

    response = client.do_action_with_exception(request)
    return response

def verify_code(phone_number, code):
    with shelve.open('verification_codes.db') as db:
        if phone_number in db:
            data = db[phone_number]
            # 检查验证码是否匹配且未过期(5分钟)
            if data['code'] == code and datetime.now() - data['timestamp'] <= timedelta(minutes=5):
                return True
    return False

本文转自 https://juejin.cn/post/7316349124599758884,如有侵权,请联系删除。

---------------------------END---------------------------

题外话

在这里插入图片描述

感兴趣的小伙伴,赠送全套Python学习资料,包含面试题、简历资料等具体看下方。

👉CSDN大礼包🎁:全网最全《Python学习资料》免费赠送🆓!(安全链接,放心点击)

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。

img

二、Python兼职渠道推荐*

学的同时助你创收,每天花1-2小时兼职,轻松稿定生活费.
在这里插入图片描述

三、最新Python学习笔记

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。

img

四、实战案例

纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

img

👉CSDN大礼包🎁:全网最全《Python学习资料》免费赠送🆓!(安全链接,放心点击)

若有侵权,请联系删除

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐