實現修改密碼接口
請求方式: POST
修改請求參數 : /change_pwd/
業務處理流程:
驗證手機號是否注冊 (格式, ajax請求檢查)
原密碼是否正確 (格式,null, 數據庫檢查)
新密碼是否正確 (格式, null, 存數據庫)
參數 | 是否前端傳入 | 描述 | 類型 |
mobile | 是 | 用戶輸入的手機號 | 字符串 |
old_password | 是 | 用戶輸入要修改的密碼 | 字符串 |
new_password | 是 | 用戶輸入的新密碼 | 字符串 |
sms_code | 是 | 用戶輸入的短信驗證碼 | 字符串 |
注:由於是post請求,在向后端發起請求時,需要附帶csrf token
前端代碼 (畢竟是前端發送ajax請求的)

$(function () { let $mobile = $('#mobile'); let $smsCodeBtn = $('.form-item .sms-captcha'); // 獲取短信驗證碼按鈕元素,需要定義一個id為input_smscode let $submit = $('.form-contain'); // 手機號檢測 $mobile.blur(function () { fn_check_mobile(); }); // 短信驗證碼發送 $smsCodeBtn.click(function () { // 判斷手機號是否輸入 if (fn_check_mobile() !== "success") { return } let SdataParams = { "mobile": $mobile.val(), // 獲取用戶輸入的手機號 }; $.ajax({ //請求地址 url : "/change_pwd/sms_code/", //請求方式 type: "POST", data: JSON.stringify(SdataParams), contentType: "application/json; charset=utf-8", dataType : "json", async: false, }) .done(function (res) { if (res.errno === "0") { // 倒計時60秒,60秒后允許用戶再次點擊發送短信驗證碼的按鈕 message.showSuccess('短信驗證碼發送成功'); let num = 60; // 設置一個計時器 let t = setInterval(function () { if (num === 1) { // 如果計時器到最后, 清除計時器對象 clearInterval(t); // 將點擊獲取驗證碼的按鈕展示的文本恢復成原始文本 $smsCodeBtn.html("獲取驗證碼"); } else { num -= 1; // 展示倒計時信息 $smsCodeBtn.html(num + "秒"); } }, 1000); } else { message.showError(res.errmsg); } }) .fail(function () { message.showError('服務器超時,請重試!'); }); }); // 確認修改密碼 $submit.submit(function (e) { e.preventDefault(); //獲取用戶輸入的內容 let sMobile = $mobile.val(); let soldPassword = $("input[name=old_password]").val(); let snewPassword = $("input[name=new_password]").val(); let sSmsCode = $("input[name=sms_captcha]").val(); if (fn_check_mobile() !== "success") { return } // 判斷用戶輸入的密碼是否為空 if ((!soldPassword) || (!snewPassword)) { message.showError('密碼或確認密碼不能為空'); return } // 判斷用戶輸入的密碼和確認密碼長度是否為6-20位 if (!(/^[0-9A-Za-z]{6,20}$/).test(snewPassword)) { message.showError('新密碼的長度需在6~20位以內'); return } // 判斷用戶輸入的密碼和確認密碼長度是否為6-20位 if (!(/^[0-9A-Za-z]{6,20}$/).test(soldPassword)) { message.showError('原密碼的長度需在6~20位以內'); return } // 密碼不能一樣 if (soldPassword == snewPassword) { message.showError('原密碼和新密碼一致,請重新檢查並輸入'); return } //短信驗證碼格式 if (!(/^\d{6}$/).test(sSmsCode)) { message.showError('短信驗證碼格式不正確,必須為6位數字!'); return } //發起POST請求 let SdataParams = { "mobile": sMobile, "old_password": soldPassword, "new_password": snewPassword, "sms_code": sSmsCode, }; $.ajax({ url: "/change_pwd/", type: "POST", headers: { "X-CSRFToken": getCookie("csrf_token") }, data: JSON.stringify(SdataParams), contentType: "application/json; charset=utf-8", dataType: "json", }) .done(function (res) { if (res.errno === "0") { // 注冊成功 message.showSuccess('恭喜你, 修改成功!'); setTimeout(function () { // 注冊成功之后重定向到主頁 window.location.href = document.referrer; }, 1000) } else { // 注冊失敗,打印錯誤信息 message.showError(res.errmsg); } }) .fail(function(){ message.showError('服務器超時,請重試!'); }); }); // 檢查手機號是否被注冊 function fn_check_mobile() { let sMobile = $mobile.val(); // 獲取用戶輸入的手機號碼字符串 let sReturnValue = ""; if (sMobile === "") { message.showError('手機號不能為空'); return } if (!(/^1[345789]\d{9}$/).test(sMobile)) { message.showError('手機號碼格式不正確,請重新輸入!'); return } $.ajax({ url: 'change_pwd/mobiles/' + sMobile + '/', type: 'GET', dataType: 'json', async: false }) .done(function (res) { if (res.data.count == 0) { message.showError(res.data.mobile + '尚未注冊,請重新輸入!'); sReturnValue = "" } else { message.showSuccess(res.data.mobile + '號碼正確'); sReturnValue = "success" } }) .fail(function () { message.showError('服務器超時,請重試!'); sReturnValue = "" }); return sReturnValue } function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { let cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { let cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } });
后端

class ChangePwdMobile(View): """ Check whether the user exists in ChangePwd page GET mobiles/(?P<mobile>1[3-9]\d{9})/ """ def get(self, request, mobile): data = { 'mobile': mobile, 'count': Users.objects.filter(mobile=mobile).count() } return to_json_data(data=data)

class ChangePwdSmsCode(View): """ send sms_code in changePwd """ def post(self, request): try: json_data = request.body if not json_data: return to_json_data(errno=Code.PARAMERR, errmsg="參數為空,請重新輸入") dict_data = json.loads(json_data.decode('utf8')) except Exception as e: logger.info('錯誤信息: {}'.format(e)) return to_json_data(errno=Code.UNKOWNERR, errmsg="未知錯誤") mobile = dict_data.get('mobile') if not mobile: return to_json_data(errno=Code.PARAMERR, errmsg='參數錯誤') # 發送短信頻繁 try: con_redis = get_redis_connection(alias='changePwd_codes') except Exception as e: # 日志器 return to_json_data(Code.UNKOWNERR, errmsg='未知錯誤') send_flag = con_redis.get('sms_flag_{}'.format(mobile)) if send_flag: return to_json_data(errno=Code.DATAEXIST, errmsg='發送短信頻繁') sms_num = '%06d' % random.randint(0, 999999) print(sms_num) # 保存 redis_con = get_redis_connection(alias='changePwd_codes') # 短信驗證碼 寫key sms_text = "sms_{}".format(mobile).encode('utf-8') # 過期時間 sms_flag = "sms_flag_{}".format(mobile).encode('utf-8') p2 = redis_con.pipeline() # 保存驗證碼 try: p2.setex(sms_text, constant.SMS_CODE_REDIS_EXPIRES, sms_num) p2.setex(sms_flag, constant.SEND_SMS_CODE_INTERVAL, 1) p2.execute() except Exception as e: logger.debug("redis 執行出現異常 {}".format(e)) return to_json_data(errno=Code.UNKOWNERR, errmsg=error_map[Code.UNKOWNERR]) # 發送驗證碼 logging.info("發送驗證碼短信【成功】[mobile:{}, sms_code:{}]".format(mobile, sms_num)) return to_json_data(errno=Code.OK, errmsg="短信驗證碼發送成功")

class ChangePwd(View): """ get : change_pwd page post: submit """ def get(self, request): return render(request, 'users/change_pwd.html') def post(self, request): json_str = request.body if not json_str: return to_json_data(errno=Code.PARAMERR, errmsg='參數為空') dict_data = json.loads(json_str.decode('utf-8')) mobile = dict_data.get('mobile') old_password = dict_data.get('old_password') new_password = dict_data.get('new_password') sms_code = dict_data.get('sms_code') # 是否為空 if not all([mobile, old_password, new_password, sms_code]): return HttpResponseForbidden('輸入為空') # 手機格式 if not re.match('^1[3-9]\d{9}$', mobile): return HttpResponseForbidden('手機號碼格式輸入錯誤') # 原密碼格式錯誤 if not re.match('^[0-9A-Za-z]{6,20}$', old_password): return HttpResponseForbidden('新密碼格式不正確') # 新密碼格式 if not re.match('^[0-9A-Za-z]{6,20}$', new_password): return HttpResponseForbidden('新密碼格式不正確') # 原密碼和新密碼 if new_password == old_password: return HttpResponseForbidden('原密碼和新密碼相同,請重試') # 驗證碼格式是否正確 if not sms_code.isnumeric(): return ("請重新檢查你的驗證碼是否正確 Forms ") # 拿到當前對象user user = Users.objects.get(mobile=mobile) if user: if check_password(old_password, user.password): user.set_password(new_password) user.save() return to_json_data(errno=Code.OK, errmsg='恭喜你修改成功') else: return to_json_data(errno=Code.PARAMERR, errmsg='原密碼錯誤') else: return to_json_data(errno=Code.PARAMERR, errmsg='不存在當前用戶')
URL配置
path('change_pwd/', views.ChangePwd.as_view(), name='change_pwd'),