完成重置密码功能
This commit is contained in:
parent
ab91c7b5a6
commit
88ce641fda
@ -23,10 +23,20 @@ public class AuthorizeController {
|
|||||||
@Resource
|
@Resource
|
||||||
AuthorizeService service;
|
AuthorizeService service;
|
||||||
|
|
||||||
@PostMapping("/valid-email")
|
@PostMapping("/valid-register-email")
|
||||||
public RestBean<String> validateEmail(@Pattern(regexp = EMAIL_REGEX) @RequestParam("email") String email,
|
public RestBean<String> validateRegisterEmail(@Pattern(regexp = EMAIL_REGEX) @RequestParam("email") String email,
|
||||||
HttpSession session){
|
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)
|
if (s == null)
|
||||||
return RestBean.success("邮件已发送,请注意查收");
|
return RestBean.success("邮件已发送,请注意查收");
|
||||||
else
|
else
|
||||||
@ -46,5 +56,30 @@ public class AuthorizeController {
|
|||||||
return RestBean.failure(400, s);
|
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.Insert;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface UserMapper {
|
public interface UserMapper {
|
||||||
@ -12,4 +13,7 @@ public interface UserMapper {
|
|||||||
|
|
||||||
@Insert("insert into db_account (email, username, password) values (#{email}, #{username}, #{password})")
|
@Insert("insert into db_account (email, username, password) values (#{email}, #{username}, #{password})")
|
||||||
int createAccount(String username, String password, String email);
|
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;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
|
||||||
public interface AuthorizeService extends 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 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
|
@Override
|
||||||
public String sendValidateEmail(String email, String sessionId) {
|
public String sendValidateEmail(String email, String sessionId, boolean hasAccount) {
|
||||||
String key = "email:" + sessionId + ":" + email;
|
String key = "email:" + sessionId + ":" + email + ":" +hasAccount;
|
||||||
if(Boolean.TRUE.equals(template.hasKey(key))) {
|
if(Boolean.TRUE.equals(template.hasKey(key))) {
|
||||||
Long expire = Optional.ofNullable(template.getExpire(key, TimeUnit.SECONDS)).orElse(0L);
|
Long expire = Optional.ofNullable(template.getExpire(key, TimeUnit.SECONDS)).orElse(0L);
|
||||||
if(expire > 120) return "请求频繁,请稍后再试";
|
if(expire > 120) return "请求频繁,请稍后再试";
|
||||||
}
|
}
|
||||||
if(mapper.findAccountByNameOrEmail(email) != null)
|
Account account = mapper.findAccountByNameOrEmail(email);
|
||||||
return "此邮箱已被其他用户注册";
|
if(hasAccount && account == null) return "没有此邮件地址的账户";
|
||||||
|
if(!hasAccount && account != null) return "此邮箱已被其他用户注册";
|
||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
int code = random.nextInt(899999) + 100000;
|
int code = random.nextInt(899999) + 100000;
|
||||||
SimpleMailMessage message = new SimpleMailMessage();
|
SimpleMailMessage message = new SimpleMailMessage();
|
||||||
@ -78,11 +79,14 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateAndRegister(String username, String password, String email, String code, String sessionId) {
|
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))) {
|
if(Boolean.TRUE.equals(template.hasKey(key))) {
|
||||||
String s = template.opsForValue().get(key);
|
String s = template.opsForValue().get(key);
|
||||||
if(s == null) return "验证码失效,请重新请求";
|
if(s == null) return "验证码失效,请重新请求";
|
||||||
if(s.equals(code)) {
|
if(s.equals(code)) {
|
||||||
|
Account account = mapper.findAccountByNameOrEmail(username);
|
||||||
|
if(account != null) return "此用户名已被注册,请更换用户名";
|
||||||
|
template.delete(key);
|
||||||
password = encoder.encode(password);
|
password = encoder.encode(password);
|
||||||
if (mapper.createAccount(username, password, email) > 0) {
|
if (mapper.createAccount(username, password, email) > 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -96,4 +100,27 @@ public class AuthorizeServiceImpl implements AuthorizeService {
|
|||||||
return "请先请求一封验证码邮件";
|
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>
|
<template>
|
||||||
<div style="margin: 30px 20px">
|
<div>
|
||||||
<el-steps :active="active" finish-status="success" align-center>
|
<div style="margin: 30px 20px">
|
||||||
<el-step title="验证电子邮件" />
|
<el-steps :active="active" finish-status="success" align-center>
|
||||||
<el-step title="重新设定密码" />
|
<el-step title="验证电子邮件" />
|
||||||
</el-steps>
|
<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>
|
</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>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {reactive, ref} from "vue";
|
import {reactive, ref} from "vue";
|
||||||
import {EditPen, Lock, Message} from "@element-plus/icons-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 active = ref(0)
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
email: '',
|
email: '',
|
||||||
code: ''
|
code: '',
|
||||||
|
password: '',
|
||||||
|
password_repeat: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const validatePassword = (rule, value, callback) => {
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -147,7 +147,7 @@ const register = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const validateEmail = () => {
|
const validateEmail = () => {
|
||||||
post('/api/auth/valid-email', {
|
post('/api/auth/valid-register-email', {
|
||||||
email: form.email
|
email: form.email
|
||||||
}, (message) => {
|
}, (message) => {
|
||||||
ElMessage.success(message)
|
ElMessage.success(message)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user