From 1fae1e971e8fb175e5544f6b03b5210166eb4b96 Mon Sep 17 00:00:00 2001 From: LYC Date: Thu, 24 Apr 2025 14:18:49 +0800 Subject: [PATCH] =?UTF-8?q?[tag]=20=E8=A7=A3=E5=86=B3=E4=BA=86=E8=B7=A8?= =?UTF-8?q?=E5=9F=9F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/SecurityConfig.java | 22 ++++++ .../controller/AuthController.java | 9 +-- .../controller/RouteController.java | 75 +++++++++++++++++++ .../controller/WorkOrderController.java | 6 +- .../entity/employee/CustomUserDetails.java | 56 +++++++++++++- .../entity/employee/Employee.java | 26 +++++-- .../service/CustomUserDetailsService.java | 42 +++++++++++ 7 files changed, 219 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/waterquality/projectmanagement/controller/RouteController.java create mode 100644 src/main/java/com/waterquality/projectmanagement/service/CustomUserDetailsService.java diff --git a/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java b/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java index 41f8121..8704068 100644 --- a/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java +++ b/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java @@ -3,6 +3,7 @@ package com.waterquality.projectmanagement.config; import com.waterquality.projectmanagement.repository.EmployeeRepository; import jakarta.servlet.Filter; import lombok.RequiredArgsConstructor; +import org.apache.catalina.filters.CorsFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; @@ -20,6 +21,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; @Configuration @EnableWebSecurity @@ -35,6 +42,7 @@ public class SecurityConfig { http .csrf(csrf -> csrf.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .cors(cors -> cors.configurationSource(corsConfigurationSource())) // 配置 CORS .authorizeHttpRequests(authz -> authz .requestMatchers("/api/auth/**").permitAll() .anyRequest().authenticated()) @@ -44,6 +52,20 @@ public class SecurityConfig { return http.build(); } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + Collections.singletonList("*"); + config.setAllowedOrigins(Arrays.asList("http://localhost:8848")); // 替换为允许的源 + config.setAllowedHeaders(Arrays.asList("*")); // 允许的头 + config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); // 允许的方法 + source.registerCorsConfiguration("/**", config); + return source; + } + @Bean public UserDetailsService userDetailsService() { return username -> (UserDetails) employeeRepository.findByUsername(username) diff --git a/src/main/java/com/waterquality/projectmanagement/controller/AuthController.java b/src/main/java/com/waterquality/projectmanagement/controller/AuthController.java index 10f0306..b8df8a1 100644 --- a/src/main/java/com/waterquality/projectmanagement/controller/AuthController.java +++ b/src/main/java/com/waterquality/projectmanagement/controller/AuthController.java @@ -15,10 +15,7 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.AuthenticationException; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.validation.Valid; @@ -32,6 +29,8 @@ public class AuthController { private final JwtTokenProvider jwtTokenProvider; private final EmployeeRepository employeeRepository; + + @CrossOrigin @PostMapping("/login") public ResponseEntity login(@Valid @RequestBody LoginDTO dto) { try { @@ -59,7 +58,7 @@ public class AuthController { token, employee.getEmployeeId(), employee.getName(), - employee.getPosition().name() + employee.getPosition() )); } catch (Exception e) { diff --git a/src/main/java/com/waterquality/projectmanagement/controller/RouteController.java b/src/main/java/com/waterquality/projectmanagement/controller/RouteController.java new file mode 100644 index 0000000..70a58f8 --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/controller/RouteController.java @@ -0,0 +1,75 @@ +package com.waterquality.projectmanagement.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +public class RouteController { + + @GetMapping("/get-async-routes") + public Map getAsyncRoutes() { + // 模拟后端动态生成路由 + Map permissionRouter = new HashMap<>(); + permissionRouter.put("path", "/permission"); + permissionRouter.put("meta", createMeta("权限管理", "ep:lollipop", 10)); + permissionRouter.put("children", createChildren()); + + return createResponse(Collections.singletonList(permissionRouter)); + } + + private Map createMeta(String title, String icon, int rank) { + Map meta = new HashMap<>(); + meta.put("title", title); + meta.put("icon", icon); + meta.put("rank", rank); + return meta; + } + + private List> createChildren() { + Map pagePermission = new HashMap<>(); + pagePermission.put("path", "/permission/page/index"); + pagePermission.put("name", "PermissionPage"); + pagePermission.put("meta", createMeta("页面权限", null, 0)); + pagePermission.put("meta.roles", List.of("admin", "common")); + + Map buttonPermission = new HashMap<>(); + buttonPermission.put("path", "/permission/button"); + buttonPermission.put("meta", createMeta("按钮权限", null, 0)); + buttonPermission.put("children", createButtonChildren()); + + return List.of(pagePermission, buttonPermission); + } + + private List> createButtonChildren() { + Map buttonRouter = new HashMap<>(); + buttonRouter.put("path", "/permission/button/router"); + buttonRouter.put("component", "permission/button/index"); + buttonRouter.put("name", "PermissionButtonRouter"); + buttonRouter.put("meta", createButtonMeta("路由返回按钮权限", List.of("permission:btn:add", "permission:btn:edit", "permission:btn:delete"))); + + Map buttonLogin = new HashMap<>(); + buttonLogin.put("path", "/permission/button/login"); + buttonLogin.put("component", "permission/button/perms"); + buttonLogin.put("name", "PermissionButtonLogin"); + buttonLogin.put("meta", createMeta("登录接口返回按钮权限", null, 0)); + + return List.of(buttonRouter, buttonLogin); + } + + private Map createButtonMeta(String title, List auths) { + Map meta = createMeta(title, null, 0); + meta.put("auths", auths); + return meta; + } + + private Map createResponse(List> data) { + Map response = new HashMap<>(); + response.put("success", true); + response.put("data", data); + return response; + } +} \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/controller/WorkOrderController.java b/src/main/java/com/waterquality/projectmanagement/controller/WorkOrderController.java index 498a0a0..74c6ce3 100644 --- a/src/main/java/com/waterquality/projectmanagement/controller/WorkOrderController.java +++ b/src/main/java/com/waterquality/projectmanagement/controller/WorkOrderController.java @@ -29,13 +29,13 @@ public class WorkOrderController { private final WorkOrderService workOrderService; @PostMapping - @PreAuthorize("hasRole('MAINTENANCE')") + @PreAuthorize("hasAnyRole('MAINTENANCE', 'ADMIN')") public ResponseEntity> createOrder( @Valid @RequestBody WorkOrderCreateDTO dto, - @AuthenticationPrincipal UserDetails user) { + @AuthenticationPrincipal CustomUserDetails user) { // 假设 UserDetails 实现了 getUsername() 方法返回用户 ID return ResponseEntity.ok(Response.newSuccess( - workOrderService.createOrder(dto, Integer.valueOf(user.getUsername())))); + workOrderService.createOrder(dto, user.getUserID()))); } @PatchMapping("/{id}/status") diff --git a/src/main/java/com/waterquality/projectmanagement/entity/employee/CustomUserDetails.java b/src/main/java/com/waterquality/projectmanagement/entity/employee/CustomUserDetails.java index 76f026d..59f0d1c 100644 --- a/src/main/java/com/waterquality/projectmanagement/entity/employee/CustomUserDetails.java +++ b/src/main/java/com/waterquality/projectmanagement/entity/employee/CustomUserDetails.java @@ -1,9 +1,59 @@ package com.waterquality.projectmanagement.entity.employee; +import lombok.Data; +import lombok.Getter; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; -public interface CustomUserDetails extends UserDetails { - Integer getUserID(); - String getUsername(); +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +@Data +public class CustomUserDetails implements UserDetails { + + private final String username; + private final String password; + private final Integer userid; + @Getter + private String position; + private final Collection authorities; + + // 默认构造函数 + public CustomUserDetails() { + this.userid = null; + this.username = null; + this.password = null; + this.position = null; + this.authorities = Collections.emptyList(); + } + + public CustomUserDetails(String username, String password, Integer id, Integer userid, String position, Collection authorities) { + this.username = username; + this.password = password; + this.userid = userid; + this.position = position; + this.authorities = authorities; + } + + public CustomUserDetails(String username, String password, String position, List authorities,Integer id) { + this.username = username; + this.password = password; + this.position = position; + this.authorities = authorities; + this.userid = id; + } + + @Override + public Collection getAuthorities() { + return List.of(); + } + + + // 实现 getUserID 方法 + public Integer getUserID(){ + return userid; + }; + } \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/entity/employee/Employee.java b/src/main/java/com/waterquality/projectmanagement/entity/employee/Employee.java index 5a97d19..f890b76 100644 --- a/src/main/java/com/waterquality/projectmanagement/entity/employee/Employee.java +++ b/src/main/java/com/waterquality/projectmanagement/entity/employee/Employee.java @@ -1,8 +1,8 @@ package com.waterquality.projectmanagement.entity.employee; -import com.waterquality.projectmanagement.entity.department.Department; import jakarta.persistence.*; import lombok.Data; +import lombok.Getter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -12,7 +12,7 @@ import java.util.Collections; @Entity @Table(name = "employees") @Data -public class Employee implements CustomUserDetails { +public class Employee extends CustomUserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "employee_id") @@ -41,9 +41,12 @@ public class Employee implements CustomUserDetails { @Column(nullable = false, unique = true) private String username; + @Getter @Column(nullable = false) private String password; + + // 实现 UserDetails 接口方法 @Override public Collection getAuthorities() { @@ -51,13 +54,19 @@ public class Employee implements CustomUserDetails { } @Override - public boolean isAccountNonExpired() { return true; } + public boolean isAccountNonExpired() { + return super.isAccountNonExpired(); + } @Override - public boolean isAccountNonLocked() { return true; } + public boolean isAccountNonLocked() { + return super.isAccountNonLocked(); + } @Override - public boolean isCredentialsNonExpired() { return true; } + public boolean isCredentialsNonExpired() { + return super.isCredentialsNonExpired(); + } @Override public boolean isEnabled() { return status == Status.ACTIVE; } @@ -70,6 +79,11 @@ public class Employee implements CustomUserDetails { @Override public String getUsername() { - return name; // 返回用户名 + return username; // 返回用户名 } + + public String getPosition(){ + return position.name(); + } + } \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/service/CustomUserDetailsService.java b/src/main/java/com/waterquality/projectmanagement/service/CustomUserDetailsService.java new file mode 100644 index 0000000..a0722ee --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/service/CustomUserDetailsService.java @@ -0,0 +1,42 @@ +package com.waterquality.projectmanagement.service; + +import com.waterquality.projectmanagement.entity.employee.CustomUserDetails; +import com.waterquality.projectmanagement.entity.employee.Employee; +import com.waterquality.projectmanagement.repository.EmployeeRepository; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class CustomUserDetailsService implements UserDetailsService { + + private final EmployeeRepository employeeRepository; + + public CustomUserDetailsService(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + Optional optionalEmployee = employeeRepository.findByUsername(username); + + if (optionalEmployee.isEmpty()) { + throw new UsernameNotFoundException("User not found"); + } + + Employee employee = (Employee) optionalEmployee.get(); // 获取 Employee 对象 + + // 根据 position 属性设置权限 + List authorities = List.of(new SimpleGrantedAuthority("ROLE_" + employee.getPosition())); + + System.out.println(employee.getEmployeeId()); + + return new CustomUserDetails(employee.getUsername(), employee.getPassword(), employee.getPosition(), authorities,employee.getEmployeeId()); + } +} \ No newline at end of file