From 5e03d7ea5efbbcdf0bb7c89e0650942f37585334 Mon Sep 17 00:00:00 2001 From: weitang Date: Tue, 3 Jun 2025 15:00:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=8E=A5=E5=8F=A3=E5=B9=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8E=A5=E5=8F=A3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/JwtAuthenticationFilter.java | 20 ++-- .../java/com/stdproject/config/WebConfig.java | 15 ++- .../controller/AppDictionaryController.java | 39 +++---- .../controller/AppMenuController.java | 57 +++++----- .../controller/AppOptLogController.java | 100 +++++++++++------- .../stdproject/controller/AuthController.java | 93 ++++++++++++---- .../stdproject/mapper/AppOptLogMapper.java | 2 +- .../stdproject/service/IAppOptLogService.java | 3 +- .../service/impl/AppOptLogServiceImpl.java | 4 +- .../com/stdproject/utils/PasswordUtils.java | 2 +- 10 files changed, 218 insertions(+), 117 deletions(-) diff --git a/backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java b/backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java index 5e277fb..342f781 100644 --- a/backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java +++ b/backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java @@ -34,21 +34,29 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; + @Autowired + private WebConfig webConfig; + @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - + try { String jwt = getJwtFromRequest(request); - + + // 拦截器中校验 + if (webConfig.loginuserCache().get(jwt) != null) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token 已失效"); + return; + } if (StringUtils.hasText(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) { String username = jwtUtils.getUsernameFromToken(jwt); - + if (StringUtils.hasText(username)) { UserDetails userDetails = userDetailsService.loadUserByUsername(username); - + if (jwtUtils.validateToken(jwt, userDetails.getUsername())) { - UsernamePasswordAuthenticationToken authentication = + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); @@ -58,7 +66,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { } catch (Exception e) { log.error("无法设置用户认证: {}", e.getMessage()); } - + filterChain.doFilter(request, response); } diff --git a/backend/src/main/java/com/stdproject/config/WebConfig.java b/backend/src/main/java/com/stdproject/config/WebConfig.java index e207fd0..68e9fd3 100644 --- a/backend/src/main/java/com/stdproject/config/WebConfig.java +++ b/backend/src/main/java/com/stdproject/config/WebConfig.java @@ -1,5 +1,8 @@ package com.stdproject.config; +import cn.hutool.cache.Cache; +import cn.hutool.cache.CacheUtil; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -12,6 +15,14 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { + /** + * 用户缓存 + */ + @Bean + public Cache loginuserCache() { + return CacheUtil.newLRUCache(200); + } + /** * 静态资源处理 */ @@ -20,9 +31,9 @@ public class WebConfig implements WebMvcConfigurer { // Swagger UI 静态资源 registry.addResourceHandler("/swagger-ui/**") .addResourceLocations("classpath:/META-INF/resources/webjars/swagger-ui/"); - + // 其他静态资源 registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/static/"); } -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/stdproject/controller/AppDictionaryController.java b/backend/src/main/java/com/stdproject/controller/AppDictionaryController.java index bbce2a5..8f55c14 100644 --- a/backend/src/main/java/com/stdproject/controller/AppDictionaryController.java +++ b/backend/src/main/java/com/stdproject/controller/AppDictionaryController.java @@ -18,6 +18,7 @@ import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; /** *

@@ -41,7 +42,7 @@ public class AppDictionaryController { public Result> page(@RequestBody @Valid PageRequest pageRequest) { Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); QueryWrapper queryWrapper = new QueryWrapper<>(); - + // 关键字搜索 if (StringUtils.hasText(pageRequest.getKeyword())) { queryWrapper.and(wrapper -> wrapper @@ -50,7 +51,7 @@ public class AppDictionaryController { .or().like("dictdata", pageRequest.getKeyword()) ); } - + // 排序 if (StringUtils.hasText(pageRequest.getOrderBy())) { if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { @@ -61,7 +62,7 @@ public class AppDictionaryController { } else { queryWrapper.orderByAsc("dictcode", "orderno"); } - + IPage result = appDictionaryService.page(page, queryWrapper); return Result.success(result); } @@ -72,7 +73,7 @@ public class AppDictionaryController { public Result> list() { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.orderByAsc("dictcode", "orderno"); - + List dictionaries = appDictionaryService.list(queryWrapper); return Result.success(dictionaries); } @@ -92,7 +93,7 @@ public class AppDictionaryController { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("dictcode", dictCode); queryWrapper.orderByAsc("orderno"); - + List dictionaries = appDictionaryService.list(queryWrapper); return Result.success(dictionaries); } @@ -106,7 +107,7 @@ public class AppDictionaryController { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("dictcode", dictCode); queryWrapper.eq("dictdata", dictData); - + AppDictionary dictionary = appDictionaryService.getOne(queryWrapper); return Result.success(dictionary); } @@ -123,18 +124,18 @@ public class AppDictionaryController { if (existDictionary != null) { return Result.error("该字典编码下的字典值已存在"); } - + // 设置默认值 if (appDictionary.getOrderno() == null) { // 获取同一字典编码下的最大序号 QueryWrapper orderQuery = new QueryWrapper<>(); - orderQuery.eq("dictcode", appDictionary.getDictcode()); + orderQuery.eq("app_id", appDictionary.getAppId()); orderQuery.orderByDesc("orderno"); orderQuery.last("LIMIT 1"); AppDictionary lastDict = appDictionaryService.getOne(orderQuery); appDictionary.setOrderno(lastDict != null ? lastDict.getOrderno() + 1 : 1); } - + appDictionary.setLastmodifydate(LocalDateTime.now()); boolean success = appDictionaryService.save(appDictionary); return success ? Result.success("新增成功") : Result.error("新增失败"); @@ -149,7 +150,7 @@ public class AppDictionaryController { if (existDictionary == null) { return Result.error("数据字典不存在"); } - + // 如果修改了字典编码或字典值,检查新的组合是否已被其他字典项使用 if (!existDictionary.getDictcode().equals(appDictionary.getDictcode()) || !existDictionary.getDictdata().equals(appDictionary.getDictdata())) { @@ -162,7 +163,7 @@ public class AppDictionaryController { return Result.error("该字典编码下的字典数据已被其他字典项使用"); } } - + appDictionary.setLastmodifydate(LocalDateTime.now()); boolean success = appDictionaryService.updateById(appDictionary); return success ? Result.success("修改成功") : Result.error("修改失败"); @@ -190,7 +191,7 @@ public class AppDictionaryController { public Result deleteByDictCode(@Parameter(description = "字典编码") @PathVariable String dictCode) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("dictcode", dictCode); - + boolean success = appDictionaryService.remove(queryWrapper); return success ? Result.success("删除成功") : Result.error("删除失败"); } @@ -202,7 +203,7 @@ public class AppDictionaryController { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("dictname", dictName); AppDictionary dictionary = appDictionaryService.getOne(queryWrapper); - + if (dictionary != null) { return Result.success(dictionary.getDictdata()); } @@ -216,13 +217,13 @@ public class AppDictionaryController { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("DISTINCT dictcode"); queryWrapper.orderByAsc("dictcode"); - + List dictionaries = appDictionaryService.list(queryWrapper); List dictCodes = dictionaries.stream() .map(AppDictionary::getDictcode) .distinct() .collect(java.util.stream.Collectors.toList()); - + return Result.success(dictCodes); } @@ -244,14 +245,14 @@ public class AppDictionaryController { @Operation(summary = "根据字典编码分组查询字典项") @GetMapping("/grouped") @OperationLog(type = "06", module = "数据字典管理", description = "根据字典编码分组查询字典项") - public Result>> getGroupedDictionaries() { + public Result>> getGroupedDictionaries() { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.orderByAsc("dictcode", "orderno"); - + List allDictionaries = appDictionaryService.list(queryWrapper); java.util.Map> groupedDict = allDictionaries.stream() .collect(java.util.stream.Collectors.groupingBy(AppDictionary::getDictcode)); - + return Result.success(groupedDict); } @@ -267,4 +268,4 @@ public class AppDictionaryController { public Integer getOrderno() { return orderno; } public void setOrderno(Integer orderno) { this.orderno = orderno; } } -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/stdproject/controller/AppMenuController.java b/backend/src/main/java/com/stdproject/controller/AppMenuController.java index d8093e9..1f5314d 100644 --- a/backend/src/main/java/com/stdproject/controller/AppMenuController.java +++ b/backend/src/main/java/com/stdproject/controller/AppMenuController.java @@ -8,6 +8,7 @@ import com.stdproject.common.PageRequest; import com.stdproject.common.Result; import com.stdproject.entity.AppMenu; import com.stdproject.service.IAppMenuService; +import com.stdproject.service.IAppUserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -37,13 +38,17 @@ public class AppMenuController { @Autowired private IAppMenuService appMenuService; + @Autowired + private IAppUserService appUserService; + + @Operation(summary = "分页查询菜单列表") @PostMapping("/page") @OperationLog(type = "06", module = "菜单管理", description = "分页查询菜单列表") public Result> page(@RequestBody @Valid PageRequest pageRequest) { Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); QueryWrapper queryWrapper = new QueryWrapper<>(); - + // 关键字搜索 if (StringUtils.hasText(pageRequest.getKeyword())) { queryWrapper.and(wrapper -> wrapper @@ -52,7 +57,7 @@ public class AppMenuController { .or().like("url", pageRequest.getKeyword()) ); } - + // 排序 if (StringUtils.hasText(pageRequest.getOrderBy())) { if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { @@ -63,7 +68,7 @@ public class AppMenuController { } else { queryWrapper.orderByAsc("parentid", "orderno"); } - + IPage result = appMenuService.page(page, queryWrapper); return Result.success(result); } @@ -74,7 +79,7 @@ public class AppMenuController { public Result> list() { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.orderByAsc("parentid", "orderno"); - + List menus = appMenuService.list(queryWrapper); return Result.success(menus); } @@ -85,7 +90,7 @@ public class AppMenuController { public Result> getMenuTree() { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.orderByAsc("parentid", "orderno"); - + List allMenus = appMenuService.list(queryWrapper); List tree = buildMenuTree(allMenus, "0"); return Result.success(tree); @@ -106,7 +111,7 @@ public class AppMenuController { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("parentid", parentId); queryWrapper.orderByAsc("orderno"); - + List children = appMenuService.list(queryWrapper); return Result.success(children); } @@ -122,7 +127,7 @@ public class AppMenuController { if (existMenu != null) { return Result.error("菜单编号已存在"); } - + // 检查父级菜单是否存在(如果不是顶级菜单) if (!"0".equals(appMenu.getParentid())) { AppMenu parentMenu = appMenuService.getById(appMenu.getParentid()); @@ -130,7 +135,7 @@ public class AppMenuController { return Result.error("父级菜单不存在"); } } - + // 设置默认值 if (appMenu.getOrderno() == null) { // 获取同级菜单的最大序号 @@ -141,20 +146,21 @@ public class AppMenuController { AppMenu lastMenu = appMenuService.getOne(orderQuery); appMenu.setOrderno(lastMenu != null ? lastMenu.getOrderno() + 1 : 1); } - + if (!StringUtils.hasText(appMenu.getIsdisplay())) { appMenu.setIsdisplay("1"); } - + if (!StringUtils.hasText(appMenu.getIslink())) { appMenu.setIslink("0"); } - + if (!StringUtils.hasText(appMenu.getType())) { appMenu.setType("01"); } - + appMenu.setLastmodifydate(LocalDateTime.now()); + appMenu.setLastmodifier(appUserService.getCurrentUsername()); boolean success = appMenuService.save(appMenu); return success ? Result.success("新增成功") : Result.error("新增失败"); } @@ -168,7 +174,7 @@ public class AppMenuController { if (existMenu == null) { return Result.error("菜单不存在"); } - + // 如果修改了菜单编号,检查新编号是否已被其他菜单使用 if (!existMenu.getCode().equals(appMenu.getCode())) { QueryWrapper queryWrapper = new QueryWrapper<>(); @@ -179,23 +185,24 @@ public class AppMenuController { return Result.error("菜单编号已被其他菜单使用"); } } - + // 如果修改了父级菜单,检查是否会形成循环引用 if (!existMenu.getParentid().equals(appMenu.getParentid())) { if (isCircularReference(appMenu.getId(), appMenu.getParentid())) { return Result.error("不能将菜单移动到自己的子菜单下"); } - + // 检查父级菜单是否存在(如果不是顶级菜单) - if (!"0".equals(appMenu.getParentid())) { + if (!"0".equals(existMenu.getParentid())) { AppMenu parentMenu = appMenuService.getById(appMenu.getParentid()); if (parentMenu == null) { return Result.error("父级菜单不存在"); } } } - + appMenu.setLastmodifydate(LocalDateTime.now()); + appMenu.setLastmodifier(appUserService.getCurrentUsername()); boolean success = appMenuService.updateById(appMenu); return success ? Result.success("修改成功") : Result.error("修改失败"); } @@ -211,7 +218,7 @@ public class AppMenuController { if (childCount > 0) { return Result.error("存在子菜单,无法删除"); } - + boolean success = appMenuService.removeById(id); return success ? Result.success("删除成功") : Result.error("删除失败"); } @@ -229,7 +236,7 @@ public class AppMenuController { return Result.error("存在子菜单的菜单无法删除"); } } - + boolean success = appMenuService.removeByIds(ids); return success ? Result.success("批量删除成功") : Result.error("批量删除失败"); } @@ -241,7 +248,7 @@ public class AppMenuController { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("type", type); queryWrapper.orderByAsc("parentid", "orderno"); - + List menus = appMenuService.list(queryWrapper); return Result.success(menus); } @@ -253,7 +260,7 @@ public class AppMenuController { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("isdisplay", "1"); queryWrapper.orderByAsc("parentid", "orderno"); - + List displayMenus = appMenuService.list(queryWrapper); List tree = buildMenuTree(displayMenus, "0"); return Result.success(tree); @@ -306,16 +313,16 @@ public class AppMenuController { if ("0".equals(newParentId)) { return false; } - + if (menuId.equals(newParentId)) { return true; } - + AppMenu parentMenu = appMenuService.getById(newParentId); if (parentMenu == null) { return false; } - + return isCircularReference(menuId, parentMenu.getParentid()); } @@ -375,4 +382,4 @@ public class AppMenuController { public Integer getOrderno() { return orderno; } public void setOrderno(Integer orderno) { this.orderno = orderno; } } -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/stdproject/controller/AppOptLogController.java b/backend/src/main/java/com/stdproject/controller/AppOptLogController.java index dd5a61c..4aa881b 100644 --- a/backend/src/main/java/com/stdproject/controller/AppOptLogController.java +++ b/backend/src/main/java/com/stdproject/controller/AppOptLogController.java @@ -1,5 +1,6 @@ package com.stdproject.controller; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -18,6 +19,7 @@ import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; /** @@ -42,16 +44,16 @@ public class AppOptLogController { public Result> page(@RequestBody @Valid PageRequest pageRequest) { Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); QueryWrapper queryWrapper = new QueryWrapper<>(); - + // 关键字搜索 if (StringUtils.hasText(pageRequest.getKeyword())) { queryWrapper.and(wrapper -> wrapper - .like("username", pageRequest.getKeyword()) - .or().like("module", pageRequest.getKeyword()) - .or().like("description", pageRequest.getKeyword()) + .like("username", pageRequest.getKeyword()) + .or().like("module", pageRequest.getKeyword()) + .or().like("description", pageRequest.getKeyword()) ); } - + // 排序 if (StringUtils.hasText(pageRequest.getOrderBy())) { if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { @@ -62,7 +64,7 @@ public class AppOptLogController { } else { queryWrapper.orderByDesc("logtime"); } - + IPage result = appOptLogService.page(page, queryWrapper); return Result.success(result); } @@ -85,7 +87,7 @@ public class AppOptLogController { queryWrapper.eq("username", username); queryWrapper.orderByDesc("logtime"); queryWrapper.last("LIMIT " + limit); - + List logs = appOptLogService.list(queryWrapper); return Result.success(logs); } @@ -100,7 +102,7 @@ public class AppOptLogController { queryWrapper.eq("type", type); queryWrapper.orderByDesc("logtime"); queryWrapper.last("LIMIT " + limit); - + List logs = appOptLogService.list(queryWrapper); return Result.success(logs); } @@ -113,9 +115,9 @@ public class AppOptLogController { @Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("module", module); - queryWrapper.orderByDesc("opttime"); + queryWrapper.orderByDesc("logtime"); queryWrapper.last("LIMIT " + limit); - + List logs = appOptLogService.list(queryWrapper); return Result.success(logs); } @@ -128,10 +130,10 @@ public class AppOptLogController { @Parameter(description = "结束时间") @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime, @Parameter(description = "限制条数") @RequestParam(defaultValue = "1000") Integer limit) { QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.between("opttime", startTime, endTime); - queryWrapper.orderByDesc("opttime"); + queryWrapper.between("logtime", startTime, endTime); + queryWrapper.orderByDesc("logtime"); queryWrapper.last("LIMIT " + limit); - + List logs = appOptLogService.list(queryWrapper); return Result.success(logs); } @@ -144,14 +146,13 @@ public class AppOptLogController { @Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("ip", ip); - queryWrapper.orderByDesc("opttime"); + queryWrapper.orderByDesc("logtime"); queryWrapper.last("LIMIT " + limit); - + List logs = appOptLogService.list(queryWrapper); return Result.success(logs); } - @Operation(summary = "删除操作日志") @DeleteMapping("/{id}") @OperationLog(type = "03", module = "操作日志管理", description = "删除操作日志") @@ -172,10 +173,9 @@ public class AppOptLogController { @DeleteMapping("/clean/{days}") @OperationLog(type = "03", module = "操作日志管理", description = "清理历史操作日志") public Result cleanOldLogs(@Parameter(description = "保留天数") @PathVariable Integer days) { - LocalDateTime cutoffTime = LocalDateTime.now().minusDays(days); - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lt("logtime", cutoffTime); - + LocalDateTime cutoff = LocalDateTime.now().minusDays(days); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.lt(AppOptLog::getLogtime, cutoff); boolean success = appOptLogService.remove(queryWrapper); return success ? Result.success("清理成功") : Result.error("清理失败"); } @@ -186,31 +186,31 @@ public class AppOptLogController { public Result getStatistics() { // 总日志数 long totalCount = appOptLogService.count(); - + // 今日日志数 LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0); QueryWrapper todayQuery = new QueryWrapper<>(); - todayQuery.ge("opttime", todayStart); + todayQuery.ge("logtime", todayStart); long todayCount = appOptLogService.count(todayQuery); - + // 本周日志数 - LocalDateTime weekStart = LocalDateTime.now().minusDays(7); + LocalDateTime weekStart = LocalDateTime.now().minusDays(7).withNano(0); QueryWrapper weekQuery = new QueryWrapper<>(); weekQuery.ge("logtime", weekStart); long weekCount = appOptLogService.count(weekQuery); - + // 本月日志数 - LocalDateTime monthStart = LocalDateTime.now().minusDays(30); + LocalDateTime monthStart = LocalDateTime.now().minusDays(30).withNano(0); QueryWrapper monthQuery = new QueryWrapper<>(); monthQuery.ge("logtime", monthStart); long monthCount = appOptLogService.count(monthQuery); - + LogStatistics statistics = new LogStatistics(); statistics.setTotalCount(totalCount); statistics.setTodayCount(todayCount); statistics.setWeekCount(weekCount); statistics.setMonthCount(monthCount); - + return Result.success(statistics); } @@ -222,7 +222,7 @@ public class AppOptLogController { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.orderByDesc("logtime"); queryWrapper.last("LIMIT " + limit); - + List logs = appOptLogService.list(queryWrapper); return Result.success(logs); } @@ -231,18 +231,42 @@ public class AppOptLogController { * 日志统计信息 */ public static class LogStatistics { + private Long totalCount; private Long todayCount; private Long weekCount; private Long monthCount; - public Long getTotalCount() { return totalCount; } - public void setTotalCount(Long totalCount) { this.totalCount = totalCount; } - public Long getTodayCount() { return todayCount; } - public void setTodayCount(Long todayCount) { this.todayCount = todayCount; } - public Long getWeekCount() { return weekCount; } - public void setWeekCount(Long weekCount) { this.weekCount = weekCount; } - public Long getMonthCount() { return monthCount; } - public void setMonthCount(Long monthCount) { this.monthCount = monthCount; } + public Long getTotalCount() { + return totalCount; + } + + public void setTotalCount(Long totalCount) { + this.totalCount = totalCount; + } + + public Long getTodayCount() { + return todayCount; + } + + public void setTodayCount(Long todayCount) { + this.todayCount = todayCount; + } + + public Long getWeekCount() { + return weekCount; + } + + public void setWeekCount(Long weekCount) { + this.weekCount = weekCount; + } + + public Long getMonthCount() { + return monthCount; + } + + public void setMonthCount(Long monthCount) { + this.monthCount = monthCount; + } } -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/stdproject/controller/AuthController.java b/backend/src/main/java/com/stdproject/controller/AuthController.java index dff7e05..0473cfe 100644 --- a/backend/src/main/java/com/stdproject/controller/AuthController.java +++ b/backend/src/main/java/com/stdproject/controller/AuthController.java @@ -3,6 +3,7 @@ package com.stdproject.controller; import com.stdproject.common.Constants; import com.stdproject.common.OperationLog; import com.stdproject.common.Result; +import com.stdproject.config.WebConfig; import com.stdproject.entity.AppUser; import com.stdproject.service.IAppUserService; import com.stdproject.utils.CaptchaUtils; @@ -20,6 +21,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; +import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -48,12 +50,14 @@ public class AuthController { @Autowired private IAppUserService appUserService; - + @Autowired + private WebConfig webConfig; /** * 登录请求类 */ public static class LoginRequest { + @NotBlank(message = "用户名不能为空") private String username; @@ -67,20 +71,44 @@ public class AuthController { private String captchaKey; // Getters and Setters - public String getUsername() { return username; } - public void setUsername(String username) { this.username = username; } - public String getPassword() { return password; } - public void setPassword(String password) { this.password = password; } - public String getCaptcha() { return captcha; } - public void setCaptcha(String captcha) { this.captcha = captcha; } - public String getCaptchaKey() { return captchaKey; } - public void setCaptchaKey(String captchaKey) { this.captchaKey = captchaKey; } + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getCaptcha() { + return captcha; + } + + public void setCaptcha(String captcha) { + this.captcha = captcha; + } + + public String getCaptchaKey() { + return captchaKey; + } + + public void setCaptchaKey(String captchaKey) { + this.captchaKey = captchaKey; + } } /** * 修改密码请求类 */ public static class ChangePasswordRequest { + @NotBlank(message = "原密码不能为空") private String oldPassword; @@ -88,10 +116,21 @@ public class AuthController { private String newPassword; // Getters and Setters - public String getOldPassword() { return oldPassword; } - public void setOldPassword(String oldPassword) { this.oldPassword = oldPassword; } - public String getNewPassword() { return newPassword; } - public void setNewPassword(String newPassword) { this.newPassword = newPassword; } + public String getOldPassword() { + return oldPassword; + } + + public void setOldPassword(String oldPassword) { + this.oldPassword = oldPassword; + } + + public String getNewPassword() { + return newPassword; + } + + public void setNewPassword(String newPassword) { + this.newPassword = newPassword; + } } /** @@ -128,7 +167,8 @@ public class AuthController { @Operation(summary = "用户登录", description = "用户登录认证") @PostMapping("/login") @OperationLog(type = Constants.OPT_TYPE_LOGIN, module = "认证管理", description = "用户登录") - public Result> login(@Valid @RequestBody LoginRequest loginRequest, HttpServletRequest request) { + public Result> login(@Valid @RequestBody LoginRequest loginRequest, + HttpServletRequest request) { try { // 注意:在实际应用中,应该从会话或其他存储中获取验证码进行验证 // 此处简化处理,假设验证码已通过(实际应用中需要实现验证逻辑) @@ -136,17 +176,17 @@ public class AuthController { // 进行身份认证 Authentication authentication = authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken( - loginRequest.getUsername(), - loginRequest.getPassword() - ) + new UsernamePasswordAuthenticationToken( + loginRequest.getUsername(), + loginRequest.getPassword() + ) ); - AppUser user=appUserService.findByUsername(loginRequest.getUsername()); + AppUser user = appUserService.findByUsername(loginRequest.getUsername()); // 设置认证信息到安全上下文 SecurityContextHolder.getContext().setAuthentication(authentication); // 生成JWT Token - String token = jwtUtils.generateToken(user.getUsername(),user.getId()); + String token = jwtUtils.generateToken(user.getUsername(), user.getId()); Map result = new HashMap<>(); result.put("token", token); @@ -172,10 +212,10 @@ public class AuthController { String token = request.getHeader(Constants.JWT_HEADER); if (token != null && token.startsWith(Constants.JWT_PREFIX)) { token = token.substring(Constants.JWT_PREFIX.length()); - // 注意:在实际应用中,应该实现Token失效机制 // 可以考虑使用短期Token或其他方式实现Token失效 // 此处省略Token黑名单实现 + webConfig.loginuserCache().put(token, "1"); } // 清除安全上下文 @@ -216,14 +256,16 @@ public class AuthController { @Operation(summary = "修改密码", description = "修改当前用户密码") @PostMapping("/changePassword") @OperationLog(type = Constants.OPT_TYPE_UPDATE, module = "认证管理", description = "修改密码") - public Result changePassword(@Valid @RequestBody ChangePasswordRequest request, HttpServletRequest httpRequest) { + public Result changePassword(@Valid @RequestBody ChangePasswordRequest request, + HttpServletRequest httpRequest) { try { String token = httpRequest.getHeader(Constants.JWT_HEADER); if (token != null && token.startsWith(Constants.JWT_PREFIX)) { token = token.substring(Constants.JWT_PREFIX.length()); String username = jwtUtils.getUsernameFromToken(token); - boolean success = appUserService.changePassword(username, request.getOldPassword(), request.getNewPassword()); + boolean success = appUserService.changePassword(username, request.getOldPassword(), + request.getNewPassword()); if (success) { return Result.success(); } else { @@ -262,5 +304,10 @@ public class AuthController { } } + @GetMapping("/getExpirationDateFromToken") + public Result getExpirationDateFromToken(String token) { + Date expirationDateFromToken = jwtUtils.getExpirationDateFromToken(token); + return Result.success(expirationDateFromToken); + } } diff --git a/backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java b/backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java index 5308b74..002134e 100644 --- a/backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java +++ b/backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java @@ -15,4 +15,4 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface AppOptLogMapper extends BaseMapper { -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/stdproject/service/IAppOptLogService.java b/backend/src/main/java/com/stdproject/service/IAppOptLogService.java index 7382c2b..9e570ec 100644 --- a/backend/src/main/java/com/stdproject/service/IAppOptLogService.java +++ b/backend/src/main/java/com/stdproject/service/IAppOptLogService.java @@ -2,6 +2,7 @@ package com.stdproject.service; import com.baomidou.mybatisplus.extension.service.IService; import com.stdproject.entity.AppOptLog; +import org.apache.ibatis.annotations.Delete; /** *

@@ -13,4 +14,4 @@ import com.stdproject.entity.AppOptLog; */ public interface IAppOptLogService extends IService { -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java index 07d32a6..e8441d8 100644 --- a/backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java +++ b/backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java @@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.stdproject.entity.AppOptLog; import com.stdproject.mapper.AppOptLogMapper; import com.stdproject.service.IAppOptLogService; +import org.apache.ibatis.annotations.Delete; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** @@ -17,4 +19,4 @@ import org.springframework.stereotype.Service; @Service public class AppOptLogServiceImpl extends ServiceImpl implements IAppOptLogService { -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/stdproject/utils/PasswordUtils.java b/backend/src/main/java/com/stdproject/utils/PasswordUtils.java index 401ef9a..86b324d 100644 --- a/backend/src/main/java/com/stdproject/utils/PasswordUtils.java +++ b/backend/src/main/java/com/stdproject/utils/PasswordUtils.java @@ -82,4 +82,4 @@ public class PasswordUtils { return hasUpper && hasLower && hasDigit && hasSpecial; } -} \ No newline at end of file +}