Harden front authentication responses

This commit is contained in:
王鹏
2026-05-22 10:01:45 +08:00
parent 276da1cb20
commit 265ec9553b
3 changed files with 105 additions and 9 deletions

View File

@@ -40,7 +40,9 @@ public class FrontAuthController extends BaseController
public AjaxResult login(@RequestBody FrontLoginBody body) public AjaxResult login(@RequestBody FrontLoginBody body)
{ {
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
String token = frontAuthService.login(body.getUsername(), body.getPassword()); String username = body == null ? null : body.getUsername();
String password = body == null ? null : body.getPassword();
String token = frontAuthService.login(username, password);
ajax.put(Constants.TOKEN, token); ajax.put(Constants.TOKEN, token);
return ajax; return ajax;
} }
@@ -48,7 +50,7 @@ public class FrontAuthController extends BaseController
@GetMapping("/profile") @GetMapping("/profile")
public AjaxResult profile() public AjaxResult profile()
{ {
return AjaxResult.success(frontUserService.selectById(SecurityUtils.getUserId())); return AjaxResult.success(frontAuthService.profile(SecurityUtils.getUserId()));
} }
@PostMapping("/logout") @PostMapping("/logout")

View File

@@ -25,10 +25,16 @@ public class FrontAuthService
public String login(String username, String password) public String login(String username, String password)
{ {
FrontUser frontUser = frontUserService.selectByUsername(username); if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
if (frontUser == null)
{ {
throw new ServiceException("前台账号或密码错误"); throw credentialException();
}
FrontUser frontUser = frontUserService.selectByUsername(username);
if (frontUser == null || StringUtils.isEmpty(frontUser.getPassword())
|| !matchesPassword(password, frontUser.getPassword()))
{
throw credentialException();
} }
if (UserStatus.DISABLE.getCode().equals(frontUser.getStatus())) if (UserStatus.DISABLE.getCode().equals(frontUser.getStatus()))
{ {
@@ -38,10 +44,6 @@ public class FrontAuthService
{ {
throw new ServiceException("前台账号已删除"); throw new ServiceException("前台账号已删除");
} }
if (!SecurityUtils.matchesPassword(password, frontUser.getPassword()))
{
throw new ServiceException("前台账号或密码错误");
}
SysUser tokenUser = new SysUser(); SysUser tokenUser = new SysUser();
tokenUser.setUserId(frontUser.getUserId()); tokenUser.setUserId(frontUser.getUserId());
@@ -55,4 +57,31 @@ public class FrontAuthService
frontUserService.updateLastLoginTime(frontUser.getUserId()); frontUserService.updateLastLoginTime(frontUser.getUserId());
return token; return token;
} }
public FrontUser profile(Long userId)
{
FrontUser frontUser = frontUserService.selectById(userId);
if (frontUser != null)
{
frontUser.setPassword(null);
}
return frontUser;
}
private boolean matchesPassword(String password, String encodedPassword)
{
try
{
return SecurityUtils.matchesPassword(password, encodedPassword);
}
catch (IllegalArgumentException e)
{
return false;
}
}
private ServiceException credentialException()
{
return new ServiceException("用户名或密码错误");
}
} }

View File

@@ -2,6 +2,7 @@ package com.ruoyi.web.service.front;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.web.service.TokenService; import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.generator.domain.front.FrontUser; import com.ruoyi.generator.domain.front.FrontUser;
@@ -15,7 +16,11 @@ import org.mockito.junit.MockitoJUnitRunner;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -63,6 +68,66 @@ public class FrontAuthServiceTest
verify(frontUserService).updateLastLoginTime(100L); verify(frontUserService).updateLastLoginTime(100L);
} }
@Test
public void loginRejectsNullPasswordWithCredentialFailure()
{
try
{
frontAuthService.login("demo", null);
fail("Expected ServiceException");
}
catch (ServiceException e)
{
assertEquals("用户名或密码错误", e.getMessage());
}
verify(tokenService, never()).createToken(any(LoginUser.class));
verify(frontUserService, never()).updateLastLoginTime(anyLong());
}
@Test
public void loginRejectsBadPasswordBeforeAccountStatus()
{
FrontUser user = new FrontUser();
user.setUserId(100L);
user.setUsername("demo");
user.setNickname("Demo");
user.setPassword(SecurityUtils.encryptPassword("admin123"));
user.setStatus("1");
user.setDelFlag("0");
when(frontUserService.selectByUsername("demo")).thenReturn(user);
try
{
frontAuthService.login("demo", "wrong");
fail("Expected ServiceException");
}
catch (ServiceException e)
{
assertEquals("用户名或密码错误", e.getMessage());
}
verify(tokenService, never()).createToken(any(LoginUser.class));
verify(frontUserService, never()).updateLastLoginTime(anyLong());
}
@Test
public void profileClearsPasswordBeforeReturning()
{
FrontUser user = new FrontUser();
user.setUserId(100L);
user.setUsername("demo");
user.setPassword("encoded-password");
when(frontUserService.selectById(100L)).thenReturn(user);
FrontUser profile = frontAuthService.profile(100L);
assertEquals("demo", profile.getUsername());
assertNull(profile.getPassword());
}
private void setField(String name, Object value) throws Exception private void setField(String name, Object value) throws Exception
{ {
Field field = FrontAuthService.class.getDeclaredField(name); Field field = FrontAuthService.class.getDeclaredField(name);