γεια σας,我是Charlie!
在Day25当中我们完成了Email订单通知,而今天我们将完成忘记密码的部分。
================================◉‿◉=================================
我们的忘记密码是要做成Email验证的机制,所以必须要在使用者按下忘记密码後後端发送Email,让使用者点选Email中的连结後可以重设密码。
所以我们先建立一个新的APP:resetPWD,并且加上URL连结:
keyboardmarket\urls.py
url('reset',include('resetPWD.urls')),
resetPWD\urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$',views.resetPWD)
]
接着是views的部分,这里的话会分成三种:
第一种是POST请求,而第二种是GET请求,第三种是PUT请求。
而我们这边的TOKEN产生使用PyJWT,因为需要有期限、加密,故这边使用。
首先先建立产生token跟解译token的方法:
def makeResetToken(user):
key = "Your random generate key"
now = datetime.datetime.now()
expiretime = now + datetime.timedelta(hours = 1)
username = user.name
payload = {
"username":username,
"exp":expiretime.timestamp()
}
return jwt.encode(payload,key,algorithm = 'HS256')
def decodeResetToken(token):
key = "Your random generate key"
try:
res = jwt.decode(token,key,algorithms = ['HS256'])
except jwt.ExpiredSignatureError:
return R.badRequest("验证超时,请重新操作!")
except Exception as e:
return R.internalServerError(str(e))
else:
return res["username"]
接着我们先建立post里面的基本程序码:
if request.method == "POST":
req = request.body
data = json.loads(req)
if "username" not in data:
return R.badRequest("username does not exist!")
user = User.objects.filter(name = data["username"])
if not user:
return R.badRequest("user not found!")
token = makeResetToken(user[0])
return R.ok("reset password request success")
能产生token之後,接着我们要发送token到使用者的email,在templates当中建立reset资料夹,建立resetpassword.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>重设密码</title>
</head>
<body>
<h1>{{ username }}您好</h1>
<p>您在keyboardmarket发起了重置密码的请求</p>
<p>密码重置连结为:</p>
<p>{{ token }}</p>
<p>请在一小时内完成重置密码动作,否则失效</p>
<hr>
<p>本信件为自动发送,请勿回覆</p>
</body>
</html>
接着在emailClient中新建send_reset_message方法:
def send_reset_message(self,
username,
token,
user_email):
email_template = render_to_string(
'reset/resetpassword.html',
{
"username":username,
"token":"http://localhost:8080/#/reset?token=" + token
}
)
email = EmailMessage(
"键盘贸易 - 重设密码通知信",
email_template,
self.EMAIL_HOST_USER,
[user_email]
)
email.content_subtype = 'html'
email.fail_silently = False
email.send()
然後到resetPWD views中新增寄送方法:
token = makeResetToken(user[0])
username = user[0].name
user_email = user[0].email
client.send_reset_message(username,token,user_email)
return R.ok("reset password request success")
再来是GET方法,GET方法是验证token是否合法,所以在GET方法中建立检查:
if request.method == "GET":
req = request.GET
if "token" not in req:
return R.badRequest("token not found")
token = req["token"]
username = decodeResetToken(token)
if type(username) != str:
return username
user = User.objects.filter(name = username)
if not user:
return R.badRequest("user not found")
return R.ok("request is valid")
再来是PUT方法,修改密码的部分:
if request.method == "PUT":
req = request.body
data = json.loads(req)
if "password" not in data or "token" not in data:
return R.badRequest("required parameter not found")
username = decodeResetToken(data["token"])
if type(username) != str:
return username
user = User.objects.filter(name = username)
if not user:
return R.badRequest("User not found")
user = user[0]
md5 = hashlib.md5()
passwordString = data["password"] + username
md5.update(passwordString.encode())
pwd = md5.hexdigest()
user.password = pwd
user.save()
return R.ok("update success")
再来是前端的部分,先在loginPage里面加上超连结:
<a href="/#/createreset">忘记密码?</a>
接着在components当中建立createreset.vue,让使用者可以输入用户名称以获取email讯息:
<template>
<html lang="zh-Hant-TW">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" type="image/x-con" href="@/assets/favicon.ico">
<div id="app">
<headerComponent></headerComponent>
<div id="resetHeader" style="width:100%;height:100px;background-image: linear-gradient(to right,#C9C9C9,#F2FFFF,#00E6E6);padding-top: 40px;">
<h3>重置密码</h3>
</div>
<div id="resetForm">
<b-form @submit="onSubmit" style="width: 100%;">
<b-form-group
id="username+group"
label="用户名:"
label-for="username"
style="margin:10px;"
>
<b-form-input
id="username"
placeholder="请输入用户名"
v-model="username"
required
>
</b-form-input>
</b-form-group>
<b-button type="submit" variant="info" style="width: 80px;margin: 10px;">发送重置连结</b-button>
<div id="result">
<p>{{ resetText }}</p>
</div>
</b-form>
</div>
</div>
</html>
</template>
接着在apis当中建立reset.js,新增发送重置密码讯息的方法:
import { host,port } from '@/apis/constant.js'
import axios from 'axios'
export function createReset(username){
return axios.post(`http://${host()}:${port()/reset`,{
"username":username
})
}
然後在createResetPage当中引入,并且新增onSubmit方法:
methods:{
onSubmit(e){
e.preventDefault()
createReset(this.username).then((response) => {
if(response.data.code == STATUS_OK){
this.resetText = "重置信发送成功,请至当初登记信箱查收"
}else{
this.resetText = response.data.data
}
})
}
}
可以测试看看能不能收的到信:
再来是reset的部分,先建立reset.vue,并加上路径:
<template>
<html lang="zh-Hant-TW">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" type="image/x-con" href="@/assets/favicon.ico">
<div id="app">
<headerComponent></headerComponent>
<div id="resetHeader" style="width:100%;height:100px;background-image: linear-gradient(to right,#C9C9C9,#F2FFFF,#00E6E6);padding-top: 40px;">
<h3>重置密码</h3>
</div>
<div id="resetForm" style="width: 50%;height: 500px;">
<b-form @submit="onSubmit" style="width:100%;">
<b-form-group
id="password_group"
label="密码:"
label-for="password"
style="margin:10px;"
>
<b-form-input
id="password"
placeholder="请输入密码"
v-model="password"
required
>
</b-form-input>
</b-form-group>
<b-form-group
id="password1_group"
label="密码2:"
label-for="password1"
style="margin:10px;"
>
<b-form-input
id="password1"
placeholder="请再次输入密码"
v-model="password1"
required
>
</b-form-input>
</b-form-group>
<b-button type="submit" variant="info" style="width: 80px;margin: 10px;">重设</b-button>
</b-form>
</div>
</div>
</html>
</template>
接着先建立验证token的API程序码:
export function resetValidate(token){
return axios.get(`http://${host()}:${port()}/reset`,{
params:{
"token":token
}
})
}
然後在vue创立时验证:
created(){
var token = this.$route.query.token
resetValidate(token).then((response) => {
if(request.data.code == STATUS_OK){
this.$fire({type:"success",text:"token验证成功,请进行重置"})
}else{
this.$fire({type:"error",text:response.data.data}).then(() => {
location.href = "/#/index"
})
}
})
}
接着创立重置密码的API方法,在reset.js中新增resetPassword方法:
export function resetPassword(password,token){
return axios.put(`http://${host()}:${port()}/reset`,{
"password":password,
"token":token
})
}
并修改onSubmit方法,成功的话则返回login Page:
onSubmit(e){
e.preventDefault()
if(this.password != this.password1){
this.$fire({type:"error",text:"两次密码不一致"}).then(() => {
return
})
}
var token = this.$route.query.token
resetPassword(this.password,token).then((response) => {
if(response.data.code == STATUS_OK){
this.$fire({type:"success",text:"修改密码成功,将导回登入页"}).then(() => {
location.href = "/#/login"
})
}else{
this.$fire({type:"error",text:response.data.data}).then(() => {
location.href = "/#/index"
})
}
})
}
就可以正常修改密码了。
================================◉‿◉=================================
Day26结束了!在今天我们完成了修改密码的前端跟後端的部分,而明天我们将开始实作google recaptcha的部分。
<<: DAY25 - 网站分析工具介绍 - 质化分析工具Hotjar
今天开始来看一下彭彭的课程 Python 简介、安装、与快速开始 参考连结如下: https://w...
今天一样来讲解一星的Fibonaccimal Base 附上程序码 import static ja...
今天我们要来实作一道题目,是不是很期待呢? Question:输入两个数字,印出两数字的和 看到「和...
Android 10以上就很简单,直接使用MediaStore抓到图片路径,然後送给图片剪裁就好 i...
什麽是RWD? 响应式网页设计(Responsive Web Design),可以让不同的设备都可以...