fix:强制用户使用强密码使用邮箱验证码校验
parent
475229295a
commit
98b9097ff2
|
|
@ -1,5 +1,11 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
function createLoginFormData(data) {
|
||||
const formData = new FormData()
|
||||
Object.keys(data).forEach(key => formData.append(key, data[key]))
|
||||
return formData
|
||||
}
|
||||
|
||||
// 登录方法 - 基于 Session 认证,使用 FormData 格式
|
||||
export function login(username, password, code, rememberMe) {
|
||||
const formData = new FormData()
|
||||
|
|
@ -9,6 +15,41 @@ export function login(username, password, code, rememberMe) {
|
|||
formData.append('rememberMe', rememberMe || false)
|
||||
return request({
|
||||
url: '/login',
|
||||
headers: {
|
||||
isToken: false,
|
||||
'Content-Type': 'multipart/form-data',
|
||||
repeatSubmit: false,
|
||||
allowWarning: true
|
||||
},
|
||||
method: 'post',
|
||||
data: formData
|
||||
})
|
||||
}
|
||||
|
||||
export function resetLoginPwd(data) {
|
||||
const formData = createLoginFormData({
|
||||
username: data.username,
|
||||
oldPassword: data.oldPassword,
|
||||
newPassword: data.newPassword,
|
||||
confirmPassword: data.confirmPassword,
|
||||
emailCode: data.emailCode
|
||||
})
|
||||
return request({
|
||||
url: '/login/resetPwd',
|
||||
headers: {
|
||||
isToken: false,
|
||||
'Content-Type': 'multipart/form-data',
|
||||
repeatSubmit: false
|
||||
},
|
||||
method: 'post',
|
||||
data: formData
|
||||
})
|
||||
}
|
||||
|
||||
export function sendResetPwdEmailCode(username) {
|
||||
const formData = createLoginFormData({ username })
|
||||
return request({
|
||||
url: '/login/sendResetPwdEmailCode',
|
||||
headers: {
|
||||
isToken: false,
|
||||
'Content-Type': 'multipart/form-data',
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ const user = {
|
|||
const rememberMe = userInfo.rememberMe
|
||||
return new Promise((resolve, reject) => {
|
||||
login(username, password, code, rememberMe).then(res => {
|
||||
resolve()
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
|
|
@ -60,17 +60,16 @@ const user = {
|
|||
},
|
||||
|
||||
// 获取用户信息
|
||||
GetInfo({ commit, state }) {
|
||||
GetInfo({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo().then(res => {
|
||||
// 后端返回的数据在 res.data 中
|
||||
const data = res.data || res
|
||||
const user = data.user
|
||||
let avatar = user.avatar? '/common/download/resource?resource='+encodeURIComponent(user.avatar) : ""
|
||||
let avatar = user.avatar ? '/common/download/resource?resource=' + encodeURIComponent(user.avatar) : ""
|
||||
if (!isHttp(avatar)) {
|
||||
avatar = (isEmpty(avatar)) ? defAva : process.env.VUE_APP_BASE_API + avatar
|
||||
}
|
||||
if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
|
||||
if (data.roles && data.roles.length > 0) {
|
||||
commit('SET_ROLES', data.roles)
|
||||
commit('SET_PERMISSIONS', data.permissions)
|
||||
} else {
|
||||
|
|
@ -82,14 +81,12 @@ const user = {
|
|||
commit('SET_NAME', user.loginName)
|
||||
commit('SET_NICK_NAME', user.userName)
|
||||
commit('SET_AVATAR', avatar)
|
||||
/* 初始密码提示 */
|
||||
if(data.isDefaultModifyPwd) {
|
||||
if (data.isDefaultModifyPwd) {
|
||||
MessageBox.confirm('您的密码还是初始密码,请修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
|
||||
router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
|
||||
}).catch(() => {})
|
||||
}
|
||||
/* 过期密码提示 */
|
||||
if(!data.isDefaultModifyPwd && data.isPasswordExpired) {
|
||||
if (!data.isDefaultModifyPwd && data.isPasswordExpired) {
|
||||
MessageBox.confirm('您的密码已过期,请尽快修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
|
||||
router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
|
||||
}).catch(() => {})
|
||||
|
|
@ -102,7 +99,7 @@ const user = {
|
|||
},
|
||||
|
||||
// 退出系统 - 基于 Session 认证
|
||||
LogOut({ commit, state }) {
|
||||
LogOut({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
logout().then(() => {
|
||||
commit('SET_ROLES', [])
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@ service.interceptors.response.use(res => {
|
|||
} else if (code === 601) {
|
||||
Message({ message: msg, type: 'warning' })
|
||||
return Promise.reject('error')
|
||||
} else if (code === 301 && res.config.headers && res.config.headers.allowWarning) {
|
||||
return res.data
|
||||
} else if (code !== 200) {
|
||||
Notification.error({ title: msg })
|
||||
return Promise.reject('error')
|
||||
|
|
|
|||
|
|
@ -54,6 +54,37 @@
|
|||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-dialog
|
||||
title="修改密码"
|
||||
:visible.sync="resetPwdOpen"
|
||||
width="420px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:show-close="false"
|
||||
append-to-body
|
||||
>
|
||||
<el-form ref="resetPwdForm" :model="resetPwdForm" :rules="resetPwdRules" label-width="100px">
|
||||
<el-form-item label="旧密码" prop="oldPassword">
|
||||
<el-input v-model="resetPwdForm.oldPassword" type="password" placeholder="请输入旧密码" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码" prop="newPassword">
|
||||
<el-input v-model="resetPwdForm.newPassword" type="password" placeholder="请输入新密码" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item label="确认新密码" prop="confirmPassword">
|
||||
<el-input v-model="resetPwdForm.confirmPassword" type="password" placeholder="请确认新密码" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱验证码" prop="emailCode">
|
||||
<el-input v-model="resetPwdForm.emailCode" placeholder="请输入邮箱验证码" maxlength="6" style="width: 190px" />
|
||||
<el-button :loading="emailCodeLoading" :disabled="emailCodeCountdown > 0" @click="sendEmailCode">
|
||||
{{ emailCodeCountdown > 0 ? emailCodeCountdown + '秒后重发' : '发送验证码' }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<div class="password-tip">密码长度8-20位,需包含大小写字母、数字、特殊字符</div>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" :loading="resetPwdLoading" @click="submitResetPwd">提 交</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 底部 -->
|
||||
<div class="el-login-footer">
|
||||
<span>Copyright © 2018-2025 unissense All Rights Reserved.</span>
|
||||
|
|
@ -64,6 +95,7 @@
|
|||
<script>
|
||||
import Cookies from "js-cookie"
|
||||
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||||
import { resetLoginPwd, sendResetPwdEmailCode } from '@/api/login'
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
|
|
@ -77,6 +109,36 @@ export default {
|
|||
rememberMe: false,
|
||||
code: ""
|
||||
},
|
||||
resetPwdForm: {
|
||||
username: "",
|
||||
oldPassword: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
emailCode: ""
|
||||
},
|
||||
resetPwdOpen: false,
|
||||
resetPwdLoading: false,
|
||||
emailCodeLoading: false,
|
||||
emailCodeCountdown: 0,
|
||||
emailCodeTimer: null,
|
||||
resetPwdRules: {
|
||||
oldPassword: [
|
||||
{ required: true, trigger: "blur", message: "请输入旧密码" }
|
||||
],
|
||||
newPassword: [
|
||||
{ required: true, trigger: "blur", message: "请输入新密码" },
|
||||
{ min: 8, max: 20, trigger: "blur", message: "密码长度为8到20个字符" },
|
||||
{ pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,20}$/, trigger: "blur", message: "密码需包含大小写字母、数字、特殊字符" }
|
||||
],
|
||||
confirmPassword: [
|
||||
{ required: true, trigger: "blur", message: "请确认新密码" },
|
||||
{ validator: (rule, value, callback) => this.equalToNewPassword(rule, value, callback), trigger: "blur" }
|
||||
],
|
||||
emailCode: [
|
||||
{ required: true, trigger: "blur", message: "请输入邮箱验证码" },
|
||||
{ pattern: /^\d{6}$/, trigger: "blur", message: "邮箱验证码为6位数字" }
|
||||
]
|
||||
},
|
||||
loginRules: {
|
||||
username: [
|
||||
{ required: true, trigger: "blur", message: "请输入您的账号" }
|
||||
|
|
@ -103,9 +165,12 @@ export default {
|
|||
}
|
||||
},
|
||||
created() {
|
||||
// this.getCode()
|
||||
this.getCode()
|
||||
this.getCookie()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.clearEmailCodeTimer()
|
||||
},
|
||||
methods: {
|
||||
getCode() {
|
||||
// 基于 Session 认证,直接使用图片 URL,添加时间戳防止缓存
|
||||
|
|
@ -120,9 +185,84 @@ export default {
|
|||
this.loginForm = {
|
||||
username: username === undefined ? this.loginForm.username : username,
|
||||
password: password === undefined ? this.loginForm.password : decrypt(password),
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
|
||||
code: this.loginForm.code
|
||||
}
|
||||
},
|
||||
equalToNewPassword(rule, value, callback) {
|
||||
if (this.resetPwdForm.newPassword !== value) {
|
||||
callback(new Error("两次输入的密码不一致"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
openResetPwdDialog() {
|
||||
this.resetPwdOpen = true
|
||||
this.clearEmailCodeTimer()
|
||||
this.resetPwdForm = {
|
||||
username: this.loginForm.username,
|
||||
oldPassword: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
emailCode: ""
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.resetPwdForm) {
|
||||
this.$refs.resetPwdForm.clearValidate()
|
||||
}
|
||||
})
|
||||
},
|
||||
sendEmailCode() {
|
||||
if (!this.resetPwdForm.username) {
|
||||
this.$modal.msgError("请输入用户名")
|
||||
return
|
||||
}
|
||||
this.emailCodeLoading = true
|
||||
sendResetPwdEmailCode(this.resetPwdForm.username).then(() => {
|
||||
this.$modal.msgSuccess("验证码已发送")
|
||||
this.startEmailCodeCountdown()
|
||||
}).finally(() => {
|
||||
this.emailCodeLoading = false
|
||||
})
|
||||
},
|
||||
startEmailCodeCountdown() {
|
||||
this.clearEmailCodeTimer()
|
||||
this.emailCodeCountdown = 60
|
||||
this.emailCodeTimer = setInterval(() => {
|
||||
if (this.emailCodeCountdown <= 1) {
|
||||
this.clearEmailCodeTimer()
|
||||
} else {
|
||||
this.emailCodeCountdown--
|
||||
}
|
||||
}, 1000)
|
||||
},
|
||||
clearEmailCodeTimer() {
|
||||
if (this.emailCodeTimer) {
|
||||
clearInterval(this.emailCodeTimer)
|
||||
this.emailCodeTimer = null
|
||||
}
|
||||
this.emailCodeCountdown = 0
|
||||
},
|
||||
submitResetPwd() {
|
||||
this.$refs.resetPwdForm.validate(valid => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
this.resetPwdLoading = true
|
||||
resetLoginPwd(this.resetPwdForm).then(() => {
|
||||
this.$modal.msgSuccess("密码修改成功,请重新登录")
|
||||
this.resetPwdOpen = false
|
||||
this.$refs.loginForm.resetFields()
|
||||
this.loginForm.password = ""
|
||||
this.$nextTick(() => {
|
||||
window.location.reload()
|
||||
})
|
||||
}).catch(() => {
|
||||
}).finally(() => {
|
||||
this.resetPwdLoading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
handleLogin() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
|
|
@ -136,7 +276,18 @@ export default {
|
|||
Cookies.remove("password")
|
||||
Cookies.remove('rememberMe')
|
||||
}
|
||||
this.$store.dispatch("Login", this.loginForm).then(() => {
|
||||
this.$store.dispatch("Login", this.loginForm).then((res) => {
|
||||
if (res && res.code === 301) {
|
||||
this.resetPwdForm.username = this.loginForm.username
|
||||
this.resetPwdForm.oldPassword = this.loginForm.password
|
||||
this.resetPwdForm.newPassword = ""
|
||||
this.resetPwdForm.confirmPassword = ""
|
||||
this.resetPwdForm.emailCode = ""
|
||||
this.clearEmailCodeTimer()
|
||||
this.resetPwdOpen = true
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
this.$router.push({ path: this.redirect || "/" }).catch(()=>{})
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
|
|
@ -160,6 +311,13 @@ export default {
|
|||
background-image: url("../assets/images/login-background.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
.password-tip {
|
||||
margin-top: -5px;
|
||||
margin-bottom: 15px;
|
||||
color: #f56c6c;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.title {
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import cn.hutool.extra.mail.Mail;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.utils.ShiroUtils;
|
||||
import com.ruoyi.framework.shiro.service.SysPasswordService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.IncorrectCredentialsException;
|
||||
import org.apache.shiro.authc.UnknownAccountException;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
|
@ -33,6 +39,12 @@ import com.ruoyi.framework.web.service.ConfigService;
|
|||
@Slf4j
|
||||
public class SysLoginController extends BaseController
|
||||
{
|
||||
private static final String RESET_PWD_EMAIL_CODE_KEY = "RESET_PWD_EMAIL_CODE_";
|
||||
|
||||
private static final String RESET_PWD_EMAIL_CODE_TIME_KEY = "RESET_PWD_EMAIL_CODE_TIME_";
|
||||
|
||||
private static final long RESET_PWD_EMAIL_CODE_EXPIRE_TIME = 5 * 60 * 1000L;
|
||||
|
||||
/**
|
||||
* 是否开启记住我功能
|
||||
*/
|
||||
|
|
@ -42,6 +54,12 @@ public class SysLoginController extends BaseController
|
|||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private SysPasswordService passwordService;
|
||||
|
||||
@GetMapping("/login")
|
||||
public String login(HttpServletRequest request, HttpServletResponse response, ModelMap mmap)
|
||||
{
|
||||
|
|
@ -69,15 +87,24 @@ public class SysLoginController extends BaseController
|
|||
@ResponseBody
|
||||
public AjaxResult ajaxLogin(String username, String password, Boolean rememberMe)
|
||||
{
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(username, password, Boolean.TRUE.equals(rememberMe));
|
||||
Subject subject = SecurityUtils.getSubject();
|
||||
try
|
||||
{
|
||||
subject.login(token);
|
||||
if (!passwordService.isStrongPassword(password))
|
||||
{
|
||||
subject.logout();
|
||||
return AjaxResult.warn("当前密码不符合安全规则,请修改密码后重新登录");
|
||||
}
|
||||
return success();
|
||||
}
|
||||
catch (AuthenticationException e)
|
||||
{
|
||||
if (e instanceof UnknownAccountException || e instanceof IncorrectCredentialsException)
|
||||
{
|
||||
return error("用户名或密码错误");
|
||||
}
|
||||
String msg = "用户或密码错误";
|
||||
if (StringUtils.isNotEmpty(e.getMessage()))
|
||||
{
|
||||
|
|
@ -87,6 +114,118 @@ public class SysLoginController extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
@PostMapping("/login/sendResetPwdEmailCode")
|
||||
@ResponseBody
|
||||
public AjaxResult sendResetPwdEmailCode(String username)
|
||||
{
|
||||
if (StringUtils.isEmpty(username))
|
||||
{
|
||||
return error("请输入用户名");
|
||||
}
|
||||
SysUser user = userService.selectUserByLoginName(username);
|
||||
if (user == null)
|
||||
{
|
||||
return error("用户不存在");
|
||||
}
|
||||
if (StringUtils.isEmpty(user.getEmail()))
|
||||
{
|
||||
return error("请联系管理员绑定邮箱1");
|
||||
}
|
||||
String code = String.valueOf(ThreadLocalRandom.current().nextInt(100000, 1000000));
|
||||
try
|
||||
{
|
||||
Mail.create()
|
||||
.setTos(user.getEmail())
|
||||
.setTitle("OMS系统修改密码邮箱验证码")
|
||||
.setContent("您的修改密码邮箱验证码为:" + code + ",有效期5分钟。如非本人操作,请忽略本邮件。")
|
||||
.setHtml(false)
|
||||
.send();
|
||||
ServletUtils.getRequest().getSession().setAttribute(RESET_PWD_EMAIL_CODE_KEY + username, code);
|
||||
ServletUtils.getRequest().getSession().setAttribute(RESET_PWD_EMAIL_CODE_TIME_KEY + username, System.currentTimeMillis());
|
||||
return success("验证码已发送");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("发送修改密码邮箱验证码失败", e);
|
||||
return error("验证码发送失败,请联系管理员");
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/login/resetPwd")
|
||||
@ResponseBody
|
||||
public AjaxResult resetPwd(String username, String oldPassword, String newPassword, String confirmPassword, String emailCode)
|
||||
{
|
||||
if (StringUtils.isEmpty(username))
|
||||
{
|
||||
return error("请输入用户名");
|
||||
}
|
||||
if (StringUtils.isEmpty(emailCode))
|
||||
{
|
||||
return error("请输入邮箱验证码");
|
||||
}
|
||||
if (!StringUtils.equals(newPassword, confirmPassword))
|
||||
{
|
||||
return error("两次密码输入不一致");
|
||||
}
|
||||
if (!passwordService.isStrongPassword(newPassword))
|
||||
{
|
||||
return error("新密码长度为8-20位,且需包含大小写字母、数字、特殊字符");
|
||||
}
|
||||
SysUser user = userService.selectUserByLoginName(username);
|
||||
if (user == null)
|
||||
{
|
||||
return error("用户不存在");
|
||||
}
|
||||
if (StringUtils.isEmpty(user.getEmail()))
|
||||
{
|
||||
return error("请联系管理员绑定邮箱1");
|
||||
}
|
||||
AjaxResult emailCodeValidateResult = validateResetPwdEmailCode(username, emailCode);
|
||||
if (emailCodeValidateResult != null)
|
||||
{
|
||||
return emailCodeValidateResult;
|
||||
}
|
||||
if (!passwordService.matches(user, oldPassword))
|
||||
{
|
||||
return error("修改密码失败,旧密码错误");
|
||||
}
|
||||
if (passwordService.matches(user, newPassword))
|
||||
{
|
||||
return error("新密码不能与旧密码相同");
|
||||
}
|
||||
user.setSalt(ShiroUtils.randomSalt());
|
||||
user.setPassword(passwordService.encryptPassword(user.getLoginName(), newPassword, user.getSalt()));
|
||||
user.setPwdUpdateDate(new java.util.Date());
|
||||
if (userService.resetUserPwd(user) > 0)
|
||||
{
|
||||
ServletUtils.getRequest().getSession().removeAttribute(RESET_PWD_EMAIL_CODE_KEY + username);
|
||||
ServletUtils.getRequest().getSession().removeAttribute(RESET_PWD_EMAIL_CODE_TIME_KEY + username);
|
||||
return success("密码修改成功,请重新登录");
|
||||
}
|
||||
return error("修改密码异常,请联系管理员");
|
||||
}
|
||||
|
||||
private AjaxResult validateResetPwdEmailCode(String username, String emailCode)
|
||||
{
|
||||
Object sessionCode = ServletUtils.getRequest().getSession().getAttribute(RESET_PWD_EMAIL_CODE_KEY + username);
|
||||
Object sessionCodeTime = ServletUtils.getRequest().getSession().getAttribute(RESET_PWD_EMAIL_CODE_TIME_KEY + username);
|
||||
if (sessionCode == null || sessionCodeTime == null)
|
||||
{
|
||||
return error("请先获取邮箱验证码");
|
||||
}
|
||||
if (System.currentTimeMillis() - (Long) sessionCodeTime > RESET_PWD_EMAIL_CODE_EXPIRE_TIME)
|
||||
{
|
||||
ServletUtils.getRequest().getSession().removeAttribute(RESET_PWD_EMAIL_CODE_KEY + username);
|
||||
ServletUtils.getRequest().getSession().removeAttribute(RESET_PWD_EMAIL_CODE_TIME_KEY + username);
|
||||
return error("邮箱验证码已过期,请重新获取");
|
||||
}
|
||||
if (!StringUtils.equals(String.valueOf(sessionCode), emailCode))
|
||||
{
|
||||
return error("邮箱验证码错误");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@GetMapping("/unauth")
|
||||
public String unauth()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ shiro:
|
|||
# 首页地址
|
||||
indexUrl: /index
|
||||
# 验证码开关
|
||||
captchaEnabled: false
|
||||
captchaEnabled: true
|
||||
# 验证码类型 math 数字计算 char 字符验证
|
||||
captchaType: math
|
||||
cookie:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#错误消息
|
||||
not.null=* 必须填写
|
||||
user.jcaptcha.error=验证码错误
|
||||
user.not.exists=用户不存在/密码错误
|
||||
user.password.not.match=用户不存在/密码错误
|
||||
user.not.exists=用户名或密码错误
|
||||
user.password.not.match=用户名或密码错误
|
||||
user.password.retry.limit.count=密码输入错误{0}次
|
||||
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟
|
||||
user.password.delete=对不起,您的账号已被删除
|
||||
|
|
|
|||
|
|
@ -49,12 +49,12 @@ public class UserConstants
|
|||
public static final int USERNAME_MIN_LENGTH = 2;
|
||||
public static final int USERNAME_MAX_LENGTH = 20;
|
||||
|
||||
/**
|
||||
* 密码长度限制
|
||||
*/
|
||||
/** 密码长度限制 */
|
||||
public static final int PASSWORD_MIN_LENGTH = 5;
|
||||
public static final int PASSWORD_MAX_LENGTH = 20;
|
||||
|
||||
public static final String PASSWORD_COMPLEXITY_PATTERN = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^A-Za-z0-9]).{8,20}$";
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -305,6 +305,8 @@ public class ShiroConfig
|
|||
filterChainDefinitionMap.put("/mcp/**", "mcpBot");
|
||||
filterChainDefinitionMap.put("/logout", "logout");
|
||||
// 不需要拦截的访问
|
||||
filterChainDefinitionMap.put("/login/resetPwd", "anon");
|
||||
filterChainDefinitionMap.put("/login/sendResetPwdEmailCode", "anon");
|
||||
filterChainDefinitionMap.put("/login", "anon,captchaValidate");
|
||||
// 注册相关
|
||||
filterChainDefinitionMap.put("/register", "anon,captchaValidate");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.ruoyi.framework.shiro.service;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.annotation.PostConstruct;
|
||||
import org.apache.shiro.cache.Cache;
|
||||
import org.apache.shiro.cache.CacheManager;
|
||||
|
|
@ -10,6 +11,7 @@ import org.springframework.beans.factory.annotation.Value;
|
|||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.constant.ShiroConstants;
|
||||
import com.ruoyi.common.constant.UserConstants;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
|
||||
import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;
|
||||
|
|
@ -33,6 +35,8 @@ public class SysPasswordService
|
|||
@Value(value = "${user.password.maxRetryCount}")
|
||||
private String maxRetryCount;
|
||||
|
||||
private static final Pattern PASSWORD_COMPLEXITY_PATTERN = Pattern.compile(UserConstants.PASSWORD_COMPLEXITY_PATTERN);
|
||||
|
||||
@PostConstruct
|
||||
public void init()
|
||||
{
|
||||
|
|
@ -73,6 +77,11 @@ public class SysPasswordService
|
|||
return user.getPassword().equals(encryptPassword(user.getLoginName(), newPassword, user.getSalt()));
|
||||
}
|
||||
|
||||
public boolean isStrongPassword(String password)
|
||||
{
|
||||
return password != null && PASSWORD_COMPLEXITY_PATTERN.matcher(password).matches();
|
||||
}
|
||||
|
||||
public void clearLoginRecordCache(String loginName)
|
||||
{
|
||||
loginRecordCache.remove(loginName);
|
||||
|
|
|
|||
Loading…
Reference in New Issue