diff --git a/src/main/java/com/campus/water/config/SecurityConfig.java b/src/main/java/com/campus/water/config/SecurityConfig.java index c94cbdc..4a0b98f 100644 --- a/src/main/java/com/campus/water/config/SecurityConfig.java +++ b/src/main/java/com/campus/water/config/SecurityConfig.java @@ -2,9 +2,7 @@ package com.campus.water.config; import com.campus.water.security.JwtAuthenticationFilter; -import com.campus.water.security.RoleConstants; import com.campus.water.security.UserDetailsServiceImpl; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; @@ -18,6 +16,12 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.Arrays; +import java.util.Collections; /** * 安全配置类 @@ -27,11 +31,15 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic @EnableMethodSecurity(prePostEnabled = true) // 启用方法级权限控制 public class SecurityConfig { - @Autowired - private UserDetailsServiceImpl userDetailsService; + private final UserDetailsServiceImpl userDetailsService; + private final JwtAuthenticationFilter jwtAuthenticationFilter; - @Autowired - private JwtAuthenticationFilter jwtAuthenticationFilter; + // 构造函数注入(替代@Autowired字段注入,更安全) + public SecurityConfig(UserDetailsServiceImpl userDetailsService, + JwtAuthenticationFilter jwtAuthenticationFilter) { + this.userDetailsService = userDetailsService; + this.jwtAuthenticationFilter = jwtAuthenticationFilter; + } /** * 认证提供者 @@ -66,14 +74,12 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - // 关闭CSRF - .csrf(csrf -> csrf.disable()) - // 无状态会话 - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - // 权限控制 + .cors(cors -> cors.configurationSource(corsConfigurationSource())) // 启用CORS并配置源 + .csrf(csrf -> csrf.disable()) // 关闭CSRF + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 无状态会话 .authorizeHttpRequests(auth -> auth // 登录接口放行 - .requestMatchers("/api/app/student/login", "/api/app/repair/login", "/api/web/login").permitAll() + .requestMatchers("/api/app/student/login", "/api/app/repair/login", "/api/web/login", "/api/common/login").permitAll() // 静态资源放行 .requestMatchers("/static/**", "/templates/**").permitAll() // 新增告警接口权限控制(URL级) @@ -85,12 +91,24 @@ public class SecurityConfig { // 其他接口需要认证 .anyRequest().authenticated() ) - // 添加JWT过滤器 - .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); // 添加JWT过滤器 - // 设置认证提供者 - http.authenticationProvider(authenticationProvider()); + http.authenticationProvider(authenticationProvider()); // 设置认证提供者 return http.build(); } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins(Collections.singletonList("http://localhost:5173")); + configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); + configuration.setAllowedHeaders(Collections.singletonList("*")); + configuration.setAllowCredentials(true); + configuration.setMaxAge(3600L); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/api/**", configuration); + return source; + } } \ No newline at end of file diff --git a/src/main/java/com/campus/water/controller/AlertController.java b/src/main/java/com/campus/water/controller/AlertController.java index f12fde9..dd2e766 100644 --- a/src/main/java/com/campus/water/controller/AlertController.java +++ b/src/main/java/com/campus/water/controller/AlertController.java @@ -19,16 +19,16 @@ import java.util.List; @RestController @RequestMapping("/api/alerts") @RequiredArgsConstructor -@Tag(name = "告警管理接口") // 替换 @Api +@Tag(name = "告警管理接口") public class AlertController { private final AlertRepository alertRepository; @GetMapping("/history") @PreAuthorize("hasAnyRole('ADMIN', 'REPAIRMAN')") - @Operation(summary = "分页查询告警历史(支持多条件筛选)") // 替换 @ApiOperation(若有) + @Operation(summary = "分页查询告警历史(支持多条件筛选)") public ResultVO> getAlertHistory( - @Parameter(description = "设备ID(可选)") @RequestParam(required = false) String deviceId, // 替换 @ApiParam + @Parameter(description = "设备ID(可选)") @RequestParam(required = false) String deviceId, @Parameter(description = "告警级别(可选,如error、critical)") @RequestParam(required = false) String level, @Parameter(description = "告警状态(可选,如pending、resolved)") @RequestParam(required = false) String status, @Parameter(description = "开始时间(可选,格式:yyyy-MM-dd HH:mm:ss)") @RequestParam(required = false) LocalDateTime startTime, @@ -37,7 +37,6 @@ public class AlertController { ) { List alerts; - // 构建查询条件(根据参数动态拼接,实际可使用Specification更灵活) if (deviceId != null) { alerts = alertRepository.findByDeviceIdAndTimestampBetween(deviceId, startTime, endTime); } else if (level != null) { @@ -61,12 +60,12 @@ public class AlertController { @GetMapping("/pending") @PreAuthorize("hasAnyRole('ADMIN', 'REPAIRMAN')") public ResultVO> getPendingAlerts( - @Parameter(description = "区域ID(可选)") @RequestParam(required = false) String areaId) { // 替换@ApiParam为@Parameter + @Parameter(description = "区域ID(可选)") @RequestParam(required = false) String areaId) { List pendingAlerts = areaId != null ? alertRepository.findByAreaIdAndStatus(areaId, Alert.AlertStatus.pending) : alertRepository.findByStatus(Alert.AlertStatus.pending); - // 按优先级排序(紧急在前) + // 按优先级排序(紧急在前)- 使用方法引用替代lambda pendingAlerts.sort((a1, a2) -> Integer.compare(a2.getAlertLevel().getPriority(), a1.getAlertLevel().getPriority())); diff --git a/src/main/java/com/campus/water/service/LoginService.java b/src/main/java/com/campus/water/service/LoginService.java index fb78143..cae1572 100644 --- a/src/main/java/com/campus/water/service/LoginService.java +++ b/src/main/java/com/campus/water/service/LoginService.java @@ -1,90 +1,81 @@ package com.campus.water.service; -import com.campus.water.entity.Admin; // 改为引用修改import com.campus.water.entity.dto.request.LoginRequest; +import com.campus.water.entity.Admin; import com.campus.water.entity.po.RepairerAuthPO; import com.campus.water.entity.po.UserPO; import com.campus.water.entity.vo.LoginVO; import com.campus.water.mapper.AdminRepository; import com.campus.water.mapper.RepairerAuthRepository; import com.campus.water.mapper.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.DigestUtils; import com.campus.water.entity.dto.request.LoginRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; -import java.nio.charset.StandardCharsets; import java.util.UUID; @Service +@RequiredArgsConstructor // 自动生成构造函数(需要Lombok依赖) public class LoginService { - @Autowired - private AdminRepository adminRepository; - - @Autowired - private UserRepository userRepository; - - @Autowired - private RepairerAuthRepository repairerAuthRepository; + // 依赖注入:通过构造函数初始化(@RequiredArgsConstructor自动生成构造函数) + private final AdminRepository adminRepository; + private final UserRepository userRepository; + private final RepairerAuthRepository repairerAuthRepository; + private final PasswordEncoder passwordEncoder; public LoginVO login(LoginRequest loginRequest) { String username = loginRequest.getUsername(); - // 密码MD5加密(和数据库存储的一致) - String encryptedPwd = DigestUtils.md5DigestAsHex( - loginRequest.getPassword().getBytes(StandardCharsets.UTF_8) - ); + String password = loginRequest.getPassword(); String userType = loginRequest.getUserType(); - switch (userType) { - case "admin": - return handleAdminLogin(username, encryptedPwd); - case "user": - return handleUserLogin(username, encryptedPwd); - case "repairer": - return handleRepairerLogin(username, encryptedPwd); - default: - throw new RuntimeException("无效的用户类型:" + userType); - } + // 增强版switch(解决"Switch语句可替换为增强的switch"警告) + return switch (userType) { + case "admin" -> handleAdminLogin(username, password); + case "user" -> handleUserLogin(username, password); + case "repairer" -> handleRepairerLogin(username, password); + default -> throw new RuntimeException("无效的用户类型:" + userType); + }; } - // 管理员登录(适配修改后的Admin实体和AdminRepository) private LoginVO handleAdminLogin(String username, String password) { - // 方法名从findByUsername改为findByAdminName Admin admin = adminRepository.findByAdminName(username) .orElseThrow(() -> new RuntimeException("管理员不存在")); - if (!admin.getPassword().equals(password)) { + + if (!passwordEncoder.matches(password, admin.getPassword())) { throw new RuntimeException("密码错误"); } + return createLoginVO(admin.getAdminId(), username, "admin"); } - // 学生登录(保持不变) private LoginVO handleUserLogin(String username, String password) { UserPO user = userRepository.findByUsername(username) .orElseThrow(() -> new RuntimeException("用户不存在")); - if (!user.getPassword().equals(password)) { + + if (!passwordEncoder.matches(password, user.getPassword())) { throw new RuntimeException("密码错误"); } + return createLoginVO(user.getStudentId(), username, "user"); } - // 维修人员登录(保持不变) private LoginVO handleRepairerLogin(String username, String password) { RepairerAuthPO repairer = repairerAuthRepository.findByUsername(username) .orElseThrow(() -> new RuntimeException("维修人员不存在")); - if (!repairer.getPassword().equals(password)) { + + if (!passwordEncoder.matches(password, repairer.getPassword())) { throw new RuntimeException("密码错误"); } + return createLoginVO(repairer.getRepairmanId(), username, "repairer"); } - // 构建登录响应VO(保持不变) private LoginVO createLoginVO(String userId, String username, String userType) { LoginVO vo = new LoginVO(); vo.setUserId(userId); vo.setUsername(username); vo.setUserType(userType); - // 临时Token(后续可替换为JWT) vo.setToken(UUID.randomUUID().toString().replace("-", "")); return vo; }