@@ -144,12 +144,9 @@ public class LoginController {
|
||||
|
||||
logger.info("用户 {} 尝试登录,Session ID: {}", loginName, session.getId());
|
||||
|
||||
if (loginService.isAccountLocked(loginName)) {
|
||||
respondError(request, response,
|
||||
"账号已被锁定,请" + loginService.getAccountLockRemainingText(loginName) + "后重试");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证码先于锁定校验:需要验证码时必须先校验通过,再告知锁定状态。
|
||||
// 否则输错密码触发验证码后重新提交,只会收到“账号已被锁定”,
|
||||
// 填写的验证码对错得不到任何反馈,用户无法判断该重填哪一项。
|
||||
if (alwaysCaptcha || loginService.needCaptcha(session)) {
|
||||
if (captchaText == null || captchaText.trim().isEmpty()) {
|
||||
respondError(request, response, "请输入验证码", true);
|
||||
@@ -161,6 +158,12 @@ public class LoginController {
|
||||
}
|
||||
}
|
||||
|
||||
if (loginService.isAccountLocked(loginName)) {
|
||||
respondError(request, response,
|
||||
"账号已被锁定,请" + loginService.getAccountLockRemainingText(loginName) + "后重试");
|
||||
return;
|
||||
}
|
||||
|
||||
LocalAuthenticationResult authResult = authenticate(loginName, password);
|
||||
|
||||
if (authResult.success) {
|
||||
|
||||
@@ -165,17 +165,4 @@ public class LoginService {
|
||||
session.removeAttribute("CAPTCHA_TEXT");
|
||||
return savedText.equalsIgnoreCase(captchaText);
|
||||
}
|
||||
|
||||
/**
|
||||
* 综合判断:是否需要验证码(Session 失败 >= 3 次)
|
||||
* 如果账号已锁定,也返回 true(但 controller 会先检查锁定)
|
||||
*/
|
||||
public boolean needCaptcha(HttpSession session, String loginName) {
|
||||
// Session 级别失败 >= 3 次,需要验证码
|
||||
if (getSessionFailCount(session) >= CAPTCHA_THRESHOLD) {
|
||||
return true;
|
||||
}
|
||||
// 账号被锁定也需要验证码(但 controller 会直接拒绝)
|
||||
return isAccountLocked(loginName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<div class="form-item pwd-item">
|
||||
<input type="password" id="password_input" name="password"
|
||||
placeholder="请输入密码" autocomplete="current-password" />
|
||||
<button type="button" class="eye-btn" id="eyeBtn" aria-label="显示密码">
|
||||
<button type="button" class="eye-btn" id="eyeBtn" tabindex="-1" aria-label="显示密码">
|
||||
<svg id="js_close_eye" viewBox="0 0 1024 1024" fill="currentColor" aria-hidden="true">
|
||||
<path d="M938.666667 317.866667m-29.866667 0a29.866667 29.866667 0 1 0 59.733333 0 29.866667 29.866667 0 1 0-59.733333 0Z" />
|
||||
<path d="M876.8 454.4c6.4-6.4 12.8-14.933333 19.2-21.333333 8.533333-8.533333 6.4-23.466667-2.133333-29.866667-8.533333-8.533333-23.466667-6.4-29.866667 2.133333-85.333333 100.266667-209.066667 157.866667-341.333333 157.866667-166.4 0-317.866667-91.733333-394.666667-238.933333-6.4-10.666667-19.2-14.933333-27.733333-8.533334-10.666667 6.4-14.933333 19.2-8.533334 27.733334 14.933333 27.733333 32 53.333333 49.066667 76.8L64 499.2c-8.533333 8.533333-8.533333 23.466667 0 32 4.266667 4.266667 8.533333 6.4 14.933333 6.4 6.4 0 12.8-2.133333 17.066667-8.533333l72.533333-76.8c36.266667 40.533333 81.066667 72.533333 128 98.133333l-55.466666 102.4c-6.4 10.666667-2.133333 25.6 8.533333 32 2.133333 2.133333 6.4 2.133333 8.533333 2.133333 8.533333 0 17.066667-4.266667 21.333334-12.8l55.466666-104.533333c51.2 21.333333 106.666667 34.133333 162.133334 36.266667v106.666666c0 12.8 10.666667 23.466667 21.333333 23.466667 12.8 0 21.333333-10.666667 21.333333-23.466667v-106.666666c53.333333-2.133333 104.533333-12.8 151.466667-29.866667l55.466667 102.4c4.266667 8.533333 12.8 12.8 21.333333 12.8 2.133333 0 6.4 0 8.533333-2.133333 10.666667-6.4 12.8-19.2 8.533334-32l-53.333334-98.133334c40.533333-19.2 78.933333-44.8 113.066667-74.666666l74.666667 78.933333c4.266667 4.266667 10.666667 8.533333 17.066666 8.533333 4.266667 0 10.666667-2.133333 14.933334-6.4 8.533333-8.533333 8.533333-23.466667 0-32l-74.666667-78.933333z" />
|
||||
|
||||
Reference in New Issue
Block a user