完成重置密码功能
This commit is contained in:
parent
ab91c7b5a6
commit
88ce641fda
@ -23,10 +23,20 @@ public class AuthorizeController {
|
||||
@Resource
|
||||
AuthorizeService service;
|
||||
|
||||
@PostMapping("/valid-email")
|
||||
public RestBean<String> validateEmail(@Pattern(regexp = EMAIL_REGEX) @RequestParam("email") String email,
|
||||
@PostMapping("/valid-register-email")
|
||||
public RestBean<String> validateRegisterEmail(@Pattern(regexp = EMAIL_REGEX) @RequestParam("email") String email,
|
||||
HttpSession session){
|
||||
String s = service.sendValidateEmail(email, session.getId());
|
||||
String s = service.sendValidateEmail(email, session.getId(), false);
|
||||
if (s == null)
|
||||
return RestBean.success("邮件已发送,请注意查收");
|
||||
else
|
||||
return RestBean.failure(400, s);
|
||||
}
|
||||
|
||||
@PostMapping("/valid-reset-email")
|
||||
public RestBean<String> validateResetEmail(@Pattern(regexp = EMAIL_REGEX) @RequestParam("email") String email,
|
||||
HttpSession session){
|
||||
String s = service.sendValidateEmail(email, session.getId(), true);
|
||||
if (s == null)
|
||||
return RestBean.success("邮件已发送,请注意查收");
|
||||
else
|
||||
@ -46,5 +56,30 @@ public class AuthorizeController {
|
||||
return RestBean.failure(400, s);
|
||||
}
|
||||
|
||||
@PostMapping("/start-reset")
|
||||
public RestBean<String> startReset(@Pattern(regexp = EMAIL_REGEX) @RequestParam("email") String email,
|
||||
@Length(min = 6, max = 6) @RequestParam("code") String code,
|
||||
HttpSession session) {
|
||||
String s = service.validateOnly(email, code, session.getId());
|
||||
if(s == null) {
|
||||
session.setAttribute("reset-password", email);
|
||||
return RestBean.success();
|
||||
} else {
|
||||
return RestBean.failure(400, s);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/do-reset")
|
||||
public RestBean<String> resetPassword(@Length(min = 6, max = 16) @RequestParam("password") String password,
|
||||
HttpSession session){
|
||||
String email = (String) session.getAttribute("reset-password");
|
||||
if(email == null) {
|
||||
return RestBean.failure(401, "请先完成邮箱验证");
|
||||
} else if(service.resetPassword(password, email)){
|
||||
session.removeAttribute("reset-password");
|
||||
return RestBean.success("密码重置成功");
|
||||
} else {
|
||||
return RestBean.failure(500, "内部错误,请联系管理员");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import com.example.entity.Account;
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
@Mapper
|
||||
public interface UserMapper {
|
||||
@ -12,4 +13,7 @@ public interface UserMapper {
|
||||
|
||||
@Insert("insert into db_account (email, username, password) values (#{email}, #{username}, #{password})")
|
||||
int createAccount(String username, String password, String email);
|
||||
|
||||
@Update("update db_account set password = #{password} where email = #{email}")
|
||||
int resetPasswordByEmail(String password, String email);
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package com.example.service;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
public interface AuthorizeService extends UserDetailsService {
|
||||
String sendValidateEmail(String email, String sessionId);
|
||||
String sendValidateEmail(String email, String sessionId, boolean hasAccount);
|
||||
String validateAndRegister(String username, String password, String email, String code, String sessionId);
|
||||
String validateOnly(String email, String code, String sessionId);
|
||||
boolean resetPassword(String password, String email);
|
||||
}
|
||||
|
@ -51,14 +51,15 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sendValidateEmail(String email, String sessionId) {
|
||||
String key = "email:" + sessionId + ":" + email;
|
||||
public String sendValidateEmail(String email, String sessionId, boolean hasAccount) {
|
||||
String key = "email:" + sessionId + ":" + email + ":" +hasAccount;
|
||||
if(Boolean.TRUE.equals(template.hasKey(key))) {
|
||||
Long expire = Optional.ofNullable(template.getExpire(key, TimeUnit.SECONDS)).orElse(0L);
|
||||
if(expire > 120) return "请求频繁,请稍后再试";
|
||||
}
|
||||
if(mapper.findAccountByNameOrEmail(email) != null)
|
||||
return "此邮箱已被其他用户注册";
|
||||
Account account = mapper.findAccountByNameOrEmail(email);
|
||||
if(hasAccount && account == null) return "没有此邮件地址的账户";
|
||||
if(!hasAccount && account != null) return "此邮箱已被其他用户注册";
|
||||
Random random = new Random();
|
||||
int code = random.nextInt(899999) + 100000;
|
||||
SimpleMailMessage message = new SimpleMailMessage();
|
||||
@ -78,11 +79,14 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
||||
|
||||
@Override
|
||||
public String validateAndRegister(String username, String password, String email, String code, String sessionId) {
|
||||
String key = "email:" + sessionId + ":" + email;
|
||||
String key = "email:" + sessionId + ":" + email + ":false";
|
||||
if(Boolean.TRUE.equals(template.hasKey(key))) {
|
||||
String s = template.opsForValue().get(key);
|
||||
if(s == null) return "验证码失效,请重新请求";
|
||||
if(s.equals(code)) {
|
||||
Account account = mapper.findAccountByNameOrEmail(username);
|
||||
if(account != null) return "此用户名已被注册,请更换用户名";
|
||||
template.delete(key);
|
||||
password = encoder.encode(password);
|
||||
if (mapper.createAccount(username, password, email) > 0) {
|
||||
return null;
|
||||
@ -96,4 +100,27 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
||||
return "请先请求一封验证码邮件";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String validateOnly(String email, String code, String sessionId) {
|
||||
String key = "email:" + sessionId + ":" + email + ":true";
|
||||
if(Boolean.TRUE.equals(template.hasKey(key))) {
|
||||
String s = template.opsForValue().get(key);
|
||||
if(s == null) return "验证码失效,请重新请求";
|
||||
if(s.equals(code)) {
|
||||
template.delete(key);
|
||||
return null;
|
||||
} else {
|
||||
return "验证码错误,请检查后再提交";
|
||||
}
|
||||
} else {
|
||||
return "请先请求一封验证码邮件";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resetPassword(String password, String email) {
|
||||
password = encoder.encode(password);
|
||||
return mapper.resetPasswordByEmail(password, email) > 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,89 +1,96 @@
|
||||
<template>
|
||||
<div style="margin: 30px 20px">
|
||||
<el-steps :active="active" finish-status="success" align-center>
|
||||
<el-step title="验证电子邮件" />
|
||||
<el-step title="重新设定密码" />
|
||||
</el-steps>
|
||||
<div>
|
||||
<div style="margin: 30px 20px">
|
||||
<el-steps :active="active" finish-status="success" align-center>
|
||||
<el-step title="验证电子邮件" />
|
||||
<el-step title="重新设定密码" />
|
||||
</el-steps>
|
||||
</div>
|
||||
<transition name="el-fade-in-linear" mode="out-in">
|
||||
<div style="text-align: center;margin: 0 20px;height: 100%" v-if="active === 0">
|
||||
<div style="margin-top: 80px">
|
||||
<div style="font-size: 25px;font-weight: bold">重置密码</div>
|
||||
<div style="font-size: 14px;color: grey">请输入需要重置密码的电子邮件地址</div>
|
||||
</div>
|
||||
<div style="margin-top: 50px">
|
||||
<el-form :model="form" :rules="rules" @validate="onValidate" ref="formRef">
|
||||
<el-form-item prop="email">
|
||||
<el-input v-model="form.email" type="email" placeholder="电子邮件地址">
|
||||
<template #prefix>
|
||||
<el-icon><Message /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<el-row :gutter="10" style="width: 100%">
|
||||
<el-col :span="17">
|
||||
<el-input v-model="form.code" :maxlength="6" type="text" placeholder="请输入验证码">
|
||||
<template #prefix>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-button type="success" @click="validateEmail"
|
||||
:disabled="!isEmailValid || coldTime > 0">
|
||||
{{coldTime > 0 ? '请稍后 ' + coldTime + ' 秒' : '获取验证码'}}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div style="margin-top: 70px">
|
||||
<el-button @click="startReset()" style="width: 270px;" type="danger" plain>开始重置密码</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="el-fade-in-linear" mode="out-in">
|
||||
<div style="text-align: center;margin: 0 20px;height: 100%" v-if="active === 1">
|
||||
<div style="margin-top: 80px">
|
||||
<div style="font-size: 25px;font-weight: bold">重置密码</div>
|
||||
<div style="font-size: 14px;color: grey">请填写您的新密码,务必牢记,防止丢失</div>
|
||||
</div>
|
||||
<div style="margin-top: 50px">
|
||||
<el-form :model="form" :rules="rules" @validate="onValidate" ref="formRef">
|
||||
<el-form-item prop="password">
|
||||
<el-input v-model="form.password" :maxlength="16" type="password" placeholder="新密码">
|
||||
<template #prefix>
|
||||
<el-icon><Lock /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password_repeat">
|
||||
<el-input v-model="form.password_repeat" :maxlength="16" type="password" placeholder="重复新密码">
|
||||
<template #prefix>
|
||||
<el-icon><Lock /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div style="margin-top: 70px">
|
||||
<el-button @click="doReset()" style="width: 270px;" type="danger" plain>立即重置密码</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
<transition name="el-fade-in-linear" mode="out-in">
|
||||
<div style="text-align: center;margin: 0 20px;height: 100%" v-if="active === 0">
|
||||
<div style="margin-top: 80px">
|
||||
<div style="font-size: 25px;font-weight: bold">重置密码</div>
|
||||
<div style="font-size: 14px;color: grey">请输入需要重置密码的电子邮件地址</div>
|
||||
</div>
|
||||
<div style="margin-top: 50px">
|
||||
<el-form :model="form" :rules="rules" @validate="onValidate" ref="formRef">
|
||||
<el-form-item prop="email">
|
||||
<el-input v-model="form.email" type="email" placeholder="电子邮件地址">
|
||||
<template #prefix>
|
||||
<el-icon><Message /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<el-row :gutter="10" style="width: 100%">
|
||||
<el-col :span="17">
|
||||
<el-input v-model="form.code" :maxlength="6" type="text" placeholder="请输入验证码">
|
||||
<template #prefix>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-button type="success" @click="validateEmail"
|
||||
:disabled="!isEmailValid || coldTime > 0">
|
||||
{{coldTime > 0 ? '请稍后 ' + coldTime + ' 秒' : '获取验证码'}}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div style="margin-top: 70px">
|
||||
<el-button @click="active = 1" style="width: 270px;" type="danger" plain>开始重置密码</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="el-fade-in-linear" mode="out-in">
|
||||
<div style="text-align: center;margin: 0 20px;height: 100%" v-if="active === 1">
|
||||
<div style="margin-top: 80px">
|
||||
<div style="font-size: 25px;font-weight: bold">重置密码</div>
|
||||
<div style="font-size: 14px;color: grey">请填写您的新密码,务必牢记,防止丢失</div>
|
||||
</div>
|
||||
<div style="margin-top: 50px">
|
||||
<el-form :model="form" :rules="rules" @validate="onValidate" ref="formRef">
|
||||
<el-form-item prop="password">
|
||||
<el-input v-model="form.password" :maxlength="16" type="password" placeholder="密码">
|
||||
<template #prefix>
|
||||
<el-icon><Lock /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password_repeat">
|
||||
<el-input v-model="form.password_repeat" :maxlength="16" type="password" placeholder="重复密码">
|
||||
<template #prefix>
|
||||
<el-icon><Lock /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div style="margin-top: 70px">
|
||||
<el-button @click="active = 1" style="width: 270px;" type="danger" plain>立即重置密码</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {reactive, ref} from "vue";
|
||||
import {EditPen, Lock, Message} from "@element-plus/icons-vue";
|
||||
import {post} from "@/net";
|
||||
import {ElMessage} from "element-plus";
|
||||
import router from "@/router";
|
||||
|
||||
const active = ref(0)
|
||||
|
||||
const form = reactive({
|
||||
email: '',
|
||||
code: ''
|
||||
email: '',
|
||||
code: '',
|
||||
password: '',
|
||||
password_repeat: '',
|
||||
})
|
||||
|
||||
const validatePassword = (rule, value, callback) => {
|
||||
@ -113,6 +120,55 @@ const rules = {
|
||||
],
|
||||
}
|
||||
|
||||
const formRef = ref()
|
||||
const isEmailValid = ref(false)
|
||||
const coldTime = ref(0)
|
||||
|
||||
const onValidate = (prop, isValid) => {
|
||||
if(prop === 'email')
|
||||
isEmailValid.value = isValid
|
||||
}
|
||||
|
||||
const validateEmail = () => {
|
||||
post('/api/auth/valid-reset-email', {
|
||||
email: form.email
|
||||
}, (message) => {
|
||||
ElMessage.success(message)
|
||||
coldTime.value = 60
|
||||
setInterval(() => coldTime.value--, 1000)
|
||||
})
|
||||
}
|
||||
|
||||
const startReset = () => {
|
||||
formRef.value.validate((isValid) => {
|
||||
if(isValid) {
|
||||
post('/api/auth/start-reset', {
|
||||
email: form.email,
|
||||
code: form.code
|
||||
}, () => {
|
||||
active.value++
|
||||
})
|
||||
} else {
|
||||
ElMessage.warning('请填写电子邮件地址和验证码')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const doReset = () => {
|
||||
formRef.value.validate((isValid) => {
|
||||
if(isValid) {
|
||||
post('/api/auth/do-reset', {
|
||||
password: form.password
|
||||
}, (message) => {
|
||||
ElMessage.success(message)
|
||||
router.push('/')
|
||||
})
|
||||
} else {
|
||||
ElMessage.warning('请填写新的密码')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -147,7 +147,7 @@ const register = () => {
|
||||
}
|
||||
|
||||
const validateEmail = () => {
|
||||
post('/api/auth/valid-email', {
|
||||
post('/api/auth/valid-register-email', {
|
||||
email: form.email
|
||||
}, (message) => {
|
||||
ElMessage.success(message)
|
||||
|
Loading…
x
Reference in New Issue
Block a user