mirror of https://github.com/bjdgyc/anylink.git
Merge 54fa80526c
into abce53e008
This commit is contained in:
commit
90c82b9de7
|
@ -93,7 +93,7 @@ func authMiddleware(next http.Handler) http.Handler {
|
||||||
route := mux.CurrentRoute(r)
|
route := mux.CurrentRoute(r)
|
||||||
name := route.GetName()
|
name := route.GetName()
|
||||||
// fmt.Println("bb", r.URL.Path, name)
|
// fmt.Println("bb", r.URL.Path, name)
|
||||||
if utils.InArrStr([]string{"login", "index", "static"}, name) {
|
if utils.InArrStr([]string{"login", "index", "static", "reset_password", "forgot_password"}, name) {
|
||||||
// 不进行鉴权
|
// 不进行鉴权
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
|
|
|
@ -0,0 +1,295 @@
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/bjdgyc/anylink/base"
|
||||||
|
"github.com/bjdgyc/anylink/dbdata"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/smtp"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var forgot_interval_time = 1 * 60 // 1分钟的间隔时间(单位:秒)
|
||||||
|
var reset_interval_time = 30 // 密码重置有效期(单位: 分钟)
|
||||||
|
|
||||||
|
func GenerateResetToken(userID int) (string, error) {
|
||||||
|
fmt.Println(base.Cfg.JwtSecret)
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||||
|
"user_id": userID,
|
||||||
|
"exp": time.Now().Add(time.Duration(reset_interval_time) * time.Minute).Unix(),
|
||||||
|
})
|
||||||
|
return token.SignedString([]byte(base.Cfg.JwtSecret))
|
||||||
|
}
|
||||||
|
|
||||||
|
type CustomClaims struct {
|
||||||
|
UserID int `json:"user_id"`
|
||||||
|
jwt.StandardClaims
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidateResetToken(tokenString string) (*CustomClaims, error) {
|
||||||
|
token, err := jwt.ParseWithClaims(
|
||||||
|
tokenString,
|
||||||
|
&CustomClaims{},
|
||||||
|
func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return []byte(base.Cfg.JwtSecret), nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置密码函数
|
||||||
|
func ResetPassword(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req struct {
|
||||||
|
Token string `json:"token" binding:"required"`
|
||||||
|
Password string `json:"password" binding:"required"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
RespError(w, RespInternalErr, "json 解析失败")
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// 验证token,并获取UserID
|
||||||
|
claims, valid_err := ValidateResetToken(req.Token)
|
||||||
|
if valid_err != nil {
|
||||||
|
msg := fmt.Sprintf("验证失败, 重置链接已过期, 请重新申请。错误信息: %v", valid_err)
|
||||||
|
RespError(w, RespInternalErr, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 根据验证后的UserId 来更新用户表的密码
|
||||||
|
s := &dbdata.User{PinCode: req.Password}
|
||||||
|
update_err := dbdata.Update("Id", claims.UserID, s)
|
||||||
|
if update_err != nil {
|
||||||
|
RespError(w, RespInternalErr, "更新密码失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("更新密码成功")
|
||||||
|
// 删除重置记录表的数据
|
||||||
|
reset := dbdata.PasswordReset{UserId: claims.UserID}
|
||||||
|
del_err := dbdata.Del(&reset)
|
||||||
|
if del_err != nil {
|
||||||
|
fmt.Println("删除记录失败", del_err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("删除验证记录成功,UserId", claims.UserID)
|
||||||
|
}
|
||||||
|
RespSucess(w, "密码重置成功")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ForgotPassword(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 校验 Content-Type
|
||||||
|
if r.Header.Get("Content-Type") != "application/json" {
|
||||||
|
RespError(w, RespInternalErr, "仅支持 JSON 格式")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 解析json数据
|
||||||
|
var req struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
RespError(w, RespInternalErr, "Json 解析失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 获取用户数据
|
||||||
|
user := &dbdata.User{}
|
||||||
|
err := dbdata.One("Email", req.Email, user)
|
||||||
|
if err != nil {
|
||||||
|
RespError(w, RespInternalErr, "用户不存在 输入的地址:"+req.Email)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 检查上一次请求的时间
|
||||||
|
reset := &dbdata.PasswordReset{}
|
||||||
|
err = dbdata.One("user_id", user.Id, reset)
|
||||||
|
if err != nil {
|
||||||
|
if err == dbdata.ErrNotFound {
|
||||||
|
base.Info("此账号没有重置记录")
|
||||||
|
} else {
|
||||||
|
RespError(w, RespInternalErr, "查询重置记录失败", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 检查时间间隔是否足够
|
||||||
|
currentTime := int(time.Now().Unix())
|
||||||
|
lastRequestTime := reset.LastRequestTime
|
||||||
|
if currentTime-lastRequestTime < forgot_interval_time {
|
||||||
|
msg := fmt.Sprintf("重复的重置操作,请等待%d秒后进行重置申请", forgot_interval_time)
|
||||||
|
RespError(w, RespInternalErr, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 生成新的重置令牌
|
||||||
|
token, err := GenerateResetToken(user.Id)
|
||||||
|
if err != nil {
|
||||||
|
RespError(w, RespInternalErr, "生成token失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 开始更新或插入重置记录
|
||||||
|
reset.ExpiresAt = int(time.Now().Add(time.Duration(reset_interval_time) * time.Minute).Unix())
|
||||||
|
reset.LastRequestTime = int(time.Now().Unix())
|
||||||
|
reset.UserId = user.Id
|
||||||
|
|
||||||
|
if reset.Token == "" {
|
||||||
|
// 如果 Token 为空,说明是第一次请求,插入新记录
|
||||||
|
reset.Token = token
|
||||||
|
err = dbdata.Add(reset)
|
||||||
|
} else {
|
||||||
|
// 如果 Token 不为空,说明记录已存在,更新记录
|
||||||
|
reset.Token = token
|
||||||
|
err = dbdata.Update("user_id", reset.UserId, reset)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
RespError(w, RespInternalErr, "更新重置记录失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取邮箱服务器的配置
|
||||||
|
dataSmtp := &dbdata.SettingSmtp{}
|
||||||
|
serverConf := &dbdata.SettingOther{}
|
||||||
|
|
||||||
|
mail_err := dbdata.SettingGet(dataSmtp)
|
||||||
|
server_err := dbdata.SettingGet(serverConf)
|
||||||
|
if server_err != nil {
|
||||||
|
RespError(w, RespInternalErr, "获取服务器配置失败,请检查后台对外地址的配置")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if mail_err != nil {
|
||||||
|
RespError(w, RespInternalErr, "获取邮箱配置失败,请检查邮箱配置")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建重置链接
|
||||||
|
parsedURL, err := url.Parse(serverConf.LinkAddr)
|
||||||
|
if err != nil {
|
||||||
|
RespError(w, RespInternalErr, "解析URL失败,可能是后台配置的对外地址不符合要求")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
scheme := parsedURL.Scheme
|
||||||
|
hosts := parsedURL.Hostname()
|
||||||
|
fullURL := fmt.Sprintf("%s://%s%s", scheme, hosts, base.Cfg.AdminAddr)
|
||||||
|
resetLink := fmt.Sprintf("%s/ui/#resetPassword?token=%s", fullURL, reset.Token)
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
mail_user := dataSmtp.Username
|
||||||
|
password := dataSmtp.Password
|
||||||
|
host := dataSmtp.Host
|
||||||
|
port := strconv.Itoa(dataSmtp.Port)
|
||||||
|
toUser := req.Email
|
||||||
|
|
||||||
|
message := fmt.Sprintf("这个是vpn账号的重置链接:%s \n密码有效期%d分钟,超时请重新提交", resetLink, reset_interval_time)
|
||||||
|
if err := SendResetMail(mail_user, password, toUser, "vpn密码重置", message, host, port, false); err != nil {
|
||||||
|
RespError(w, RespInternalErr, "邮箱发送失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
RespSucess(w, "邮箱发送成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendResetMail(email, password, toEmail, subject, body, host, port string, isHtml bool) (err error) {
|
||||||
|
header := make(map[string]string)
|
||||||
|
header["From"] = "<" + email + ">"
|
||||||
|
header["To"] = toEmail
|
||||||
|
header["Subject"] = subject
|
||||||
|
if isHtml {
|
||||||
|
header["Content-Type"] = "text/html; charset=UTF-8"
|
||||||
|
} else {
|
||||||
|
header["Content-Type"] = "text/plain; charset=UTF-8"
|
||||||
|
}
|
||||||
|
|
||||||
|
message := ""
|
||||||
|
for k, v := range header {
|
||||||
|
message += fmt.Sprintf("%s: %s\r\n", k, v)
|
||||||
|
}
|
||||||
|
message += "\r\n" + body
|
||||||
|
|
||||||
|
auth := smtp.PlainAuth(
|
||||||
|
"",
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
host,
|
||||||
|
)
|
||||||
|
|
||||||
|
toEmails := strings.Split(toEmail, ";")
|
||||||
|
fmt.Println(email, password, toEmails, host, port)
|
||||||
|
err = sendMailUsingTLS(
|
||||||
|
fmt.Sprintf("%s:%s", host, port),
|
||||||
|
auth,
|
||||||
|
email,
|
||||||
|
toEmails,
|
||||||
|
[]byte(message),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("send_mail_error: %v, %v", toEmails, err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a smtp client
|
||||||
|
func dial(addr string) (*smtp.Client, error) {
|
||||||
|
conn, err := tls.Dial("tcp", addr, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Dialing Error:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//分解主机端口字符串
|
||||||
|
host, _, _ := net.SplitHostPort(addr)
|
||||||
|
return smtp.NewClient(conn, host)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendMailUsingTLS(addr string, auth smtp.Auth, from string,
|
||||||
|
to []string, msg []byte) (err error) {
|
||||||
|
|
||||||
|
//create smtp client
|
||||||
|
c, err := dial(addr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Create smpt client error:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
if auth != nil {
|
||||||
|
if ok, _ := c.Extension("AUTH"); ok {
|
||||||
|
if err = c.Auth(auth); err != nil {
|
||||||
|
fmt.Println("Error during AUTH", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.Mail(from); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range to {
|
||||||
|
if err = c.Rcpt(addr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := c.Data()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = w.Write(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Quit()
|
||||||
|
}
|
||||||
|
|
|
@ -77,6 +77,8 @@ func StartAdmin() {
|
||||||
r.HandleFunc("/user/policy/detail", PolicyDetail)
|
r.HandleFunc("/user/policy/detail", PolicyDetail)
|
||||||
r.HandleFunc("/user/policy/set", PolicySet)
|
r.HandleFunc("/user/policy/set", PolicySet)
|
||||||
r.HandleFunc("/user/policy/del", PolicyDel)
|
r.HandleFunc("/user/policy/del", PolicyDel)
|
||||||
|
r.HandleFunc("/user/reset/forgotPassword", ForgotPassword).Name("forgot_password")
|
||||||
|
r.HandleFunc("/user/reset/resetPassword", ResetPassword).Name("reset_password")
|
||||||
|
|
||||||
r.HandleFunc("/group/list", GroupList)
|
r.HandleFunc("/group/list", GroupList)
|
||||||
r.HandleFunc("/group/names", GroupNames)
|
r.HandleFunc("/group/names", GroupNames)
|
||||||
|
|
|
@ -36,7 +36,7 @@ func initDb() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化数据库
|
// 初始化数据库
|
||||||
err = xdb.Sync2(&User{}, &Setting{}, &Group{}, &IpMap{}, &AccessAudit{}, &Policy{}, &StatsNetwork{}, &StatsCpu{}, &StatsMem{}, &StatsOnline{}, &UserActLog{})
|
err = xdb.Sync2(&User{}, &Setting{}, &Group{}, &IpMap{}, &AccessAudit{}, &Policy{}, &StatsNetwork{}, &StatsCpu{}, &StatsMem{}, &StatsOnline{}, &UserActLog{}, &PasswordReset{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatal(err)
|
base.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,3 +118,9 @@ type StatsMem struct {
|
||||||
Percent float64 `json:"percent" xorm:"Float"`
|
Percent float64 `json:"percent" xorm:"Float"`
|
||||||
CreatedAt time.Time `json:"created_at" xorm:"DateTime created index"`
|
CreatedAt time.Time `json:"created_at" xorm:"DateTime created index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PasswordReset struct {
|
||||||
|
Token string `json:"token" xorm:"varchar(60) not null unique"`
|
||||||
|
UserId int `json:"id" xorm:"not null"`
|
||||||
|
ExpiresAt int `json:"expires_at" xorm:"not null"`
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,99 @@
|
||||||
|
<template>
|
||||||
|
<div class="login">
|
||||||
|
<el-card style="width: 550px;">
|
||||||
|
<div class="issuer">VPN账号密码重置申请</div>
|
||||||
|
|
||||||
|
<el-form
|
||||||
|
:model="form"
|
||||||
|
status-icon
|
||||||
|
:rules="rules"
|
||||||
|
ref="form"
|
||||||
|
label-width="120px"
|
||||||
|
class="ruleForm"
|
||||||
|
>
|
||||||
|
<el-form-item label="注册邮箱" prop="email">
|
||||||
|
<el-input v-model="form.email" placeholder="请输入注册邮箱"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
:loading="loading"
|
||||||
|
@click="submitForm('form')"
|
||||||
|
>
|
||||||
|
发送重置邮件
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from "axios"; // 移除了 qs 的导入
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ForgotPassword",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
form: {
|
||||||
|
email: ""
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
email: [
|
||||||
|
{ required: true, message: "请输入邮箱地址", trigger: "blur" },
|
||||||
|
{ type: "email", message: "请输入正确的邮箱格式", trigger: "blur" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submitForm(formName) {
|
||||||
|
this.$refs[formName].validate(valid => {
|
||||||
|
if (!valid) return false;
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
// 修改后的 POST 请求
|
||||||
|
axios.post("/user/reset/forgotPassword",
|
||||||
|
this.form, // 直接发送对象
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json' // 明确指定 JSON 格式
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
this.$message.success("重置邮件已发送,请检查您的邮箱");
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.data.msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.$message.error("服务暂时不可用");
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 样式保持不变 */
|
||||||
|
.login {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.issuer {
|
||||||
|
font-size: 24px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
color: #409EFF;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,169 @@
|
||||||
|
<template>
|
||||||
|
<div class="login">
|
||||||
|
<el-card style="width: 550px;">
|
||||||
|
<div class="issuer">VPN个人账号密码重置</div>
|
||||||
|
<el-form
|
||||||
|
:model="form"
|
||||||
|
status-icon
|
||||||
|
:rules="rules"
|
||||||
|
ref="form"
|
||||||
|
label-width="120px"
|
||||||
|
class="ruleForm"
|
||||||
|
>
|
||||||
|
<el-form-item label="新密码" prop="password">
|
||||||
|
<el-input
|
||||||
|
type="password"
|
||||||
|
v-model="form.password"
|
||||||
|
autocomplete="off"
|
||||||
|
show-password
|
||||||
|
placeholder="请输入新密码,需要大小写并且8位以上"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="确认密码" prop="checkPass">
|
||||||
|
<el-input
|
||||||
|
type="password"
|
||||||
|
v-model="form.checkPass"
|
||||||
|
autocomplete="off"
|
||||||
|
show-password
|
||||||
|
placeholder="请再次输入密码"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
:loading="loading"
|
||||||
|
@click="submitForm('form')"
|
||||||
|
>
|
||||||
|
确认重置
|
||||||
|
</el-button>
|
||||||
|
<!-- <el-button @click="$router.push('/login')">返回登录</el-button>-->
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ResetPassword",
|
||||||
|
data() {
|
||||||
|
const validatePass = (rule, value, callback) => {
|
||||||
|
if (value === "") {
|
||||||
|
callback(new Error("请输入密码"));
|
||||||
|
} else if (value.length < 8) {
|
||||||
|
callback(new Error("密码长度不能小于8位"));
|
||||||
|
} else if (
|
||||||
|
!/[A-Z]/.test(value) || // 必须包含大写字母
|
||||||
|
!/[a-z]/.test(value) || // 必须包含小写字母
|
||||||
|
!/\d/.test(value) // 必须包含数字
|
||||||
|
) {
|
||||||
|
callback(new Error("密码必须包含大小写字母和数字"));
|
||||||
|
} else {
|
||||||
|
if (this.form.checkPass !== "") {
|
||||||
|
this.$refs.form.validateField("checkPass");
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const validatePass2 = (rule, value, callback) => {
|
||||||
|
if (value === "") {
|
||||||
|
callback(new Error("请再次输入密码"));
|
||||||
|
} else if (value !== this.form.password) {
|
||||||
|
callback(new Error("两次输入密码不一致!"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
form: {
|
||||||
|
password: "",
|
||||||
|
checkPass: "",
|
||||||
|
token: ""
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
password: [
|
||||||
|
{ validator: validatePass, trigger: "blur" }
|
||||||
|
],
|
||||||
|
checkPass: [
|
||||||
|
{ validator: validatePass2, trigger: "blur" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 从URL获取token参数
|
||||||
|
this.form.token = this.$route.query.token;
|
||||||
|
if (!this.form.token) {
|
||||||
|
this.$message.error("无效的验证令牌");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submitForm(formName) {
|
||||||
|
this.$refs[formName].validate(valid => {
|
||||||
|
if (!valid) return false;
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
axios.post("/user/reset/resetPassword",
|
||||||
|
{
|
||||||
|
password: this.form.password,
|
||||||
|
token: this.form.token
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
this.$message.success("密码重置成功,关闭此页面即可!");
|
||||||
|
this.form.password = "";
|
||||||
|
this.form.checkPass = "";
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.data.msg || "重置失败");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
let message = "服务暂时不可用";
|
||||||
|
if (error.response) {
|
||||||
|
switch (error.response.status) {
|
||||||
|
case 401:
|
||||||
|
message = "验证令牌已过期";
|
||||||
|
break;
|
||||||
|
case 400:
|
||||||
|
message = "无效的请求参数";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$message.error(message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 保持相同样式 */
|
||||||
|
.login {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.issuer {
|
||||||
|
font-size: 24px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
color: #409EFF;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -7,6 +7,8 @@ Vue.use(VueRouter)
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: '/login', component: () => import('@/pages/Login') },
|
{ path: '/login', component: () => import('@/pages/Login') },
|
||||||
|
{path: '/forgotPassword', component: () => import('@/pages/reset/ForgotPassword')},
|
||||||
|
{path: '/resetPassword', component: () => import('@/pages/reset/ResetPassword')},
|
||||||
{
|
{
|
||||||
path: '/admin',
|
path: '/admin',
|
||||||
component: () => import('@/layout/Layout'),
|
component: () => import('@/layout/Layout'),
|
||||||
|
@ -47,6 +49,11 @@ router.beforeEach((to, from, next) => {
|
||||||
|
|
||||||
console.log("beforeEach", from.path, to.path, token)
|
console.log("beforeEach", from.path, to.path, token)
|
||||||
// console.log(from)
|
// console.log(from)
|
||||||
|
// 无论认证状态都允许访问重置页
|
||||||
|
if (to.path === '/forgotPassword' || to.path === '/resetPassword') {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 没有token,全都跳转到login
|
// 没有token,全都跳转到login
|
||||||
if (!token) {
|
if (!token) {
|
||||||
|
|
Loading…
Reference in New Issue