重构Service类实现,将QueryService泛型参数调整为VO类型,确保缓存VO对象而非实体。优化关联实体处理逻辑,减少重复代码。修改findById方法返回VO对象,新增getById方法获取实体。更新相关调用点以适配新接口。 调整WebSocket处理、控制器及Service实现,确保数据类型一致性。完善文档记录重构过程及发现的问题。为后续优化提供基础架构支持。
175 lines
8.1 KiB
Java
175 lines
8.1 KiB
Java
package com.ecep.contract.config;
|
||
|
||
import java.util.List;
|
||
import java.util.stream.Collectors;
|
||
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.context.annotation.Bean;
|
||
import org.springframework.context.annotation.Configuration;
|
||
import org.springframework.context.annotation.Lazy;
|
||
import org.springframework.security.authentication.AuthenticationManager;
|
||
import org.springframework.security.config.Customizer;
|
||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||
import org.springframework.security.core.GrantedAuthority;
|
||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||
import org.springframework.security.core.userdetails.User;
|
||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||
import org.springframework.security.web.SecurityFilterChain;
|
||
|
||
import com.ecep.contract.ds.other.service.EmployeeService;
|
||
import com.ecep.contract.model.Employee;
|
||
import com.ecep.contract.model.EmployeeRole;
|
||
import com.ecep.contract.vo.EmployeeVo;
|
||
|
||
/**
|
||
* Spring Security配置类
|
||
* 用于配置安全认证和授权规则
|
||
*/
|
||
@Configuration
|
||
@EnableWebSecurity
|
||
@EnableMethodSecurity(prePostEnabled = true) // 开启 @PreAuthorize 等注解
|
||
public class SecurityConfig {
|
||
|
||
@Lazy
|
||
@Autowired
|
||
private EmployeeService employeeService;
|
||
|
||
/**
|
||
* 配置HTTP安全策略
|
||
* 启用表单登录和HTTP Basic认证
|
||
*/
|
||
@Bean
|
||
public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager)
|
||
throws Exception {
|
||
http
|
||
.authorizeHttpRequests(authorize -> authorize
|
||
.requestMatchers("/login.html", "/css/**", "/js/**", "/images/**", "/webjars/**", "/login",
|
||
"/error", "/api/login", "/ws/**")
|
||
.permitAll() // 允许静态资源、登录页面、错误页面和JSON登录API访问,以及WebSocket连接
|
||
.anyRequest().authenticated() // 其他所有请求需要认证
|
||
)
|
||
.csrf(AbstractHttpConfigurer::disable) // 禁用CSRF保护,适合开发环境
|
||
.formLogin(form -> form
|
||
.loginPage("/login.html") // 直接使用静态登录页面
|
||
.loginProcessingUrl("/login") // 登录处理URL
|
||
.permitAll() // 允许所有人访问登录页面
|
||
.defaultSuccessUrl("/", true) // 登录成功后重定向到首页
|
||
.failureUrl("/login.html?error=true") // 登录失败后重定向到登录页面并显示错误
|
||
.usernameParameter("username") // 用户名参数名
|
||
.passwordParameter("password") // 密码参数名
|
||
)
|
||
.httpBasic(Customizer.withDefaults()) // 启用HTTP Basic认证
|
||
.logout(logout -> logout
|
||
.logoutUrl("/logout") // 注销URL
|
||
.logoutSuccessUrl("/login?logout=true") // 注销成功后重定向到登录页面
|
||
.invalidateHttpSession(true) // 使会话失效
|
||
.deleteCookies("JSESSIONID") // 删除会话cookie
|
||
.permitAll() // 允许所有人访问注销URL
|
||
)
|
||
.sessionManagement(session -> session
|
||
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 根据需要创建会话
|
||
.maximumSessions(1) // 每个用户最多1个会话
|
||
.expiredUrl("/login?expired=true") // 会话过期后重定向到登录页面
|
||
)
|
||
.authenticationManager(authenticationManager); // 设置认证管理器
|
||
|
||
return http.build();
|
||
}
|
||
|
||
/**
|
||
* 配置AuthenticationManager
|
||
* 用于处理认证请求
|
||
*/
|
||
@Bean
|
||
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
|
||
throws Exception {
|
||
return authenticationConfiguration.getAuthenticationManager();
|
||
}
|
||
|
||
/**
|
||
* 配置密码编码器
|
||
* BCryptPasswordEncoder是Spring Security推荐的密码编码器
|
||
*/
|
||
@Bean
|
||
public PasswordEncoder passwordEncoder() {
|
||
return new BCryptPasswordEncoder();
|
||
}
|
||
|
||
/**
|
||
* 配置基于EmployeeService的用户认证
|
||
* 通过EmployeeService获取员工信息并转换为Spring Security的UserDetails
|
||
*/
|
||
@Bean
|
||
public UserDetailsService userDetailsService() {
|
||
return username -> {
|
||
// 使用EmployeeService根据用户名查找员工
|
||
EmployeeVo employeeVo = employeeService.findByAccount(username);
|
||
|
||
// 如果找不到员工,抛出UsernameNotFoundException异常
|
||
if (employeeVo == null) {
|
||
throw new UsernameNotFoundException("用户不存在: " + username);
|
||
}
|
||
|
||
// 获取员工实体
|
||
Employee employee = employeeService.getById(employeeVo.getId());
|
||
|
||
// 检查员工是否活跃
|
||
if (!employee.isActive()) {
|
||
throw new UsernameNotFoundException("用户已禁用: " + username);
|
||
}
|
||
|
||
// 将员工角色转换为Spring Security的GrantedAuthority
|
||
List<GrantedAuthority> authorities = getAuthoritiesFromRoles(
|
||
employeeService.getRolesByEmployeeId(employee.getId()));
|
||
|
||
// 创建并返回UserDetails对象
|
||
// 注意:根据系统设计,Employee实体中没有密码字段,系统使用IP/MAC绑定认证
|
||
// 这里使用密码编码器加密后的固定密码,确保认证流程能够正常工作
|
||
return User.builder()
|
||
.username(employee.getAccount())
|
||
.password(passwordEncoder().encode("default123")) // 使用默认密码进行加密
|
||
.accountExpired(false) // 账户未过期
|
||
.accountLocked(false) // 账户未锁定
|
||
.credentialsExpired(false) // 凭证未过期
|
||
.disabled(!employee.isActive()) // 根据员工状态设置是否禁用
|
||
.authorities(authorities)
|
||
.build();
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 将EmployeeRole列表转换为Spring Security的GrantedAuthority列表
|
||
*/
|
||
private List<GrantedAuthority> getAuthoritiesFromRoles(List<EmployeeRole> roles) {
|
||
if (roles == null || roles.isEmpty()) {
|
||
return List.of();
|
||
}
|
||
|
||
// 为每个角色创建GrantedAuthority
|
||
// 系统管理员拥有ADMIN角色,其他用户拥有USER角色
|
||
return roles.stream()
|
||
.filter(EmployeeRole::isActive) // 只包含活跃的角色
|
||
.map(role -> {
|
||
if (role.isSystemAdministrator()) {
|
||
return new SimpleGrantedAuthority("ROLE_ADMIN");
|
||
} else {
|
||
return new SimpleGrantedAuthority("ROLE_USER");
|
||
}
|
||
})
|
||
.collect(Collectors.toList());
|
||
}
|
||
|
||
// Spring Security会自动配置一个使用我们定义的UserDetailsService的DaoAuthenticationProvider
|
||
// 移除显式的authenticationProvider Bean定义以避免警告
|
||
// 当同时存在AuthenticationProvider和UserDetailsService Bean时,Spring
|
||
// Security会优先使用AuthenticationProvider
|
||
// 而忽略直接的UserDetailsService,虽然这不影响功能,但会产生警告
|
||
} |