cors配置 #53

Merged
hnu202326010122 merged 2 commits from jingyou_branch into develop 1 month ago

@ -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;
}
}

@ -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<List<Alert>> 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<Alert> 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<List<Alert>> getPendingAlerts(
@Parameter(description = "区域ID可选") @RequestParam(required = false) String areaId) { // 替换@ApiParam为@Parameter
@Parameter(description = "区域ID可选") @RequestParam(required = false) String areaId) {
List<Alert> 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()));

@ -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;
}

Loading…
Cancel
Save