Files
contract-manager/server/src/main/java/com/ecep/contract/config/SecurityConfig.java
songqq 49413ad473 refactor(service): 统一Service缓存为VO对象并优化关联实体处理
重构Service类实现,将QueryService泛型参数调整为VO类型,确保缓存VO对象而非实体。优化关联实体处理逻辑,减少重复代码。修改findById方法返回VO对象,新增getById方法获取实体。更新相关调用点以适配新接口。

调整WebSocket处理、控制器及Service实现,确保数据类型一致性。完善文档记录重构过程及发现的问题。为后续优化提供基础架构支持。
2025-09-29 19:31:51 +08:00

175 lines
8.1 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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虽然这不影响功能但会产生警告
}