diff --git a/backend/src/main/java/com/imeeting/auth/JwtAuthenticationFilter.java b/backend/src/main/java/com/imeeting/auth/JwtAuthenticationFilter.java index 7c41ef0..a0c9e90 100644 --- a/backend/src/main/java/com/imeeting/auth/JwtAuthenticationFilter.java +++ b/backend/src/main/java/com/imeeting/auth/JwtAuthenticationFilter.java @@ -1,5 +1,7 @@ package com.imeeting.auth; +import com.imeeting.security.LoginUser; +import com.imeeting.service.SysPermissionService; import io.jsonwebtoken.Claims; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -12,14 +14,16 @@ import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; -import java.util.Collections; +import java.util.Set; @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenProvider jwtTokenProvider; + private final SysPermissionService sysPermissionService; - public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider) { + public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider, SysPermissionService sysPermissionService) { this.jwtTokenProvider = jwtTokenProvider; + this.sysPermissionService = sysPermissionService; } @Override @@ -31,10 +35,17 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { try { Claims claims = jwtTokenProvider.parseToken(token); String username = claims.get("username", String.class); - UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken(username, null, Collections.emptyList()); - authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - SecurityContextHolder.getContext().setAuthentication(authentication); + Long userId = claims.get("userId", Long.class); + + if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { + Set permissions = sysPermissionService.listPermissionCodesByUserId(userId); + LoginUser loginUser = new LoginUser(userId, username, permissions); + + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + } } catch (Exception ignored) { SecurityContextHolder.clearContext(); } diff --git a/backend/src/main/java/com/imeeting/config/SecurityConfig.java b/backend/src/main/java/com/imeeting/config/SecurityConfig.java index d3619e7..ea145c9 100644 --- a/backend/src/main/java/com/imeeting/config/SecurityConfig.java +++ b/backend/src/main/java/com/imeeting/config/SecurityConfig.java @@ -5,6 +5,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; 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.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -18,6 +19,7 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import java.util.List; @Configuration +@EnableMethodSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthenticationFilter jwtAuthenticationFilter) throws Exception { diff --git a/backend/src/main/java/com/imeeting/controller/DictItemController.java b/backend/src/main/java/com/imeeting/controller/DictItemController.java index 8a45be3..b61a825 100644 --- a/backend/src/main/java/com/imeeting/controller/DictItemController.java +++ b/backend/src/main/java/com/imeeting/controller/DictItemController.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.imeeting.common.ApiResponse; import com.imeeting.entity.SysDictItem; import com.imeeting.service.SysDictItemService; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -18,6 +19,7 @@ public class DictItemController { } @GetMapping + @PreAuthorize("@ss.hasPermi('sys_dict:list')") public ApiResponse> list(@RequestParam(required = false) String typeCode) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); if (typeCode != null && !typeCode.isEmpty()) { @@ -28,27 +30,32 @@ public class DictItemController { } @GetMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_dict:query')") public ApiResponse get(@PathVariable Long id) { return ApiResponse.ok(sysDictItemService.getById(id)); } @PostMapping + @PreAuthorize("@ss.hasPermi('sys_dict:create')") public ApiResponse create(@RequestBody SysDictItem dictItem) { return ApiResponse.ok(sysDictItemService.save(dictItem)); } @PutMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_dict:update')") public ApiResponse update(@PathVariable Long id, @RequestBody SysDictItem dictItem) { dictItem.setDictItemId(id); return ApiResponse.ok(sysDictItemService.updateById(dictItem)); } @DeleteMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_dict:delete')") public ApiResponse delete(@PathVariable Long id) { return ApiResponse.ok(sysDictItemService.removeById(id)); } @GetMapping("/type/{typeCode}") + @PreAuthorize("@ss.hasPermi('sys_dict:query')") public ApiResponse> getByType(@PathVariable String typeCode) { return ApiResponse.ok(sysDictItemService.getItemsByTypeCode(typeCode)); } diff --git a/backend/src/main/java/com/imeeting/controller/DictTypeController.java b/backend/src/main/java/com/imeeting/controller/DictTypeController.java index a13d0ca..fbf64f6 100644 --- a/backend/src/main/java/com/imeeting/controller/DictTypeController.java +++ b/backend/src/main/java/com/imeeting/controller/DictTypeController.java @@ -3,6 +3,7 @@ package com.imeeting.controller; import com.imeeting.common.ApiResponse; import com.imeeting.entity.SysDictType; import com.imeeting.service.SysDictTypeService; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -17,27 +18,32 @@ public class DictTypeController { } @GetMapping + @PreAuthorize("@ss.hasPermi('sys_dict:list')") public ApiResponse> list() { return ApiResponse.ok(sysDictTypeService.list()); } @GetMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_dict:query')") public ApiResponse get(@PathVariable Long id) { return ApiResponse.ok(sysDictTypeService.getById(id)); } @PostMapping + @PreAuthorize("@ss.hasPermi('sys_dict:create')") public ApiResponse create(@RequestBody SysDictType dictType) { return ApiResponse.ok(sysDictTypeService.save(dictType)); } @PutMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_dict:update')") public ApiResponse update(@PathVariable Long id, @RequestBody SysDictType dictType) { dictType.setDictTypeId(id); return ApiResponse.ok(sysDictTypeService.updateById(dictType)); } @DeleteMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_dict:delete')") public ApiResponse delete(@PathVariable Long id) { return ApiResponse.ok(sysDictTypeService.removeById(id)); } diff --git a/backend/src/main/java/com/imeeting/controller/PermissionController.java b/backend/src/main/java/com/imeeting/controller/PermissionController.java index 3165328..800dac5 100644 --- a/backend/src/main/java/com/imeeting/controller/PermissionController.java +++ b/backend/src/main/java/com/imeeting/controller/PermissionController.java @@ -6,6 +6,7 @@ import com.imeeting.dto.PermissionNode; import com.imeeting.entity.SysPermission; import com.imeeting.service.SysPermissionService; import io.jsonwebtoken.Claims; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; @@ -26,41 +27,36 @@ public class PermissionController { } @GetMapping - public ApiResponse> list(@RequestHeader("Authorization") String authorization) { - Long userId = resolveUserId(authorization); - if (userId == null || userId != 1L) { - return ApiResponse.error("Forbidden"); - } + @PreAuthorize("@ss.hasPermi('sys_permission:list')") + public ApiResponse> list() { return ApiResponse.ok(sysPermissionService.list()); } @GetMapping("/me") - public ApiResponse> myPermissions(@RequestHeader("Authorization") String authorization) { - Long userId = resolveUserId(authorization); - return ApiResponse.ok(sysPermissionService.listByUserId(userId)); + public ApiResponse> myPermissions() { + // Implementation can use SecurityContext to get current userId + return ApiResponse.ok(sysPermissionService.listByUserId(getCurrentUserId())); } @GetMapping("/tree") - public ApiResponse> tree(@RequestHeader("Authorization") String authorization) { - Long userId = resolveUserId(authorization); - if (userId == null || userId != 1L) { - return ApiResponse.error("Forbidden"); - } + @PreAuthorize("@ss.hasPermi('sys_permission:list')") + public ApiResponse> tree() { return ApiResponse.ok(buildTree(sysPermissionService.list())); } @GetMapping("/tree/me") - public ApiResponse> myTree(@RequestHeader("Authorization") String authorization) { - Long userId = resolveUserId(authorization); - return ApiResponse.ok(buildTree(sysPermissionService.listByUserId(userId))); + public ApiResponse> myTree() { + return ApiResponse.ok(buildTree(sysPermissionService.listByUserId(getCurrentUserId()))); } @GetMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_permission:query')") public ApiResponse get(@PathVariable Long id) { return ApiResponse.ok(sysPermissionService.getById(id)); } @PostMapping + @PreAuthorize("@ss.hasPermi('sys_permission:create')") public ApiResponse create(@RequestBody SysPermission perm) { String error = validateParent(perm); if (error != null) { @@ -70,6 +66,7 @@ public class PermissionController { } @PutMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_permission:update')") public ApiResponse update(@PathVariable Long id, @RequestBody SysPermission perm) { perm.setPermId(id); String error = validateParent(perm); @@ -87,17 +84,17 @@ public class PermissionController { } @DeleteMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_permission:delete')") public ApiResponse delete(@PathVariable Long id) { return ApiResponse.ok(sysPermissionService.removeById(id)); } - private Long resolveUserId(String authorization) { - if (authorization == null || !authorization.startsWith("Bearer ")) { - return null; + private Long getCurrentUserId() { + org.springframework.security.core.Authentication authentication = org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null && authentication.getPrincipal() instanceof com.imeeting.security.LoginUser) { + return ((com.imeeting.security.LoginUser) authentication.getPrincipal()).getUserId(); } - String token = authorization.substring(7); - Claims claims = jwtTokenProvider.parseToken(token); - return claims.get("userId", Long.class); + return null; } private String validateParent(SysPermission perm) { diff --git a/backend/src/main/java/com/imeeting/controller/RoleController.java b/backend/src/main/java/com/imeeting/controller/RoleController.java index 846de26..34b08c1 100644 --- a/backend/src/main/java/com/imeeting/controller/RoleController.java +++ b/backend/src/main/java/com/imeeting/controller/RoleController.java @@ -6,6 +6,7 @@ import com.imeeting.entity.SysRole; import com.imeeting.entity.SysRolePermission; import com.imeeting.mapper.SysRolePermissionMapper; import com.imeeting.service.SysRoleService; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; @@ -23,32 +24,38 @@ public class RoleController { } @GetMapping + @PreAuthorize("@ss.hasPermi('sys_role:list')") public ApiResponse> list() { return ApiResponse.ok(sysRoleService.list()); } @GetMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_role:query')") public ApiResponse get(@PathVariable Long id) { return ApiResponse.ok(sysRoleService.getById(id)); } @PostMapping + @PreAuthorize("@ss.hasPermi('sys_role:create')") public ApiResponse create(@RequestBody SysRole role) { return ApiResponse.ok(sysRoleService.save(role)); } @PutMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_role:update')") public ApiResponse update(@PathVariable Long id, @RequestBody SysRole role) { role.setRoleId(id); return ApiResponse.ok(sysRoleService.updateById(role)); } @DeleteMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_role:delete')") public ApiResponse delete(@PathVariable Long id) { return ApiResponse.ok(sysRoleService.removeById(id)); } @GetMapping("/{id}/permissions") + @PreAuthorize("@ss.hasPermi('sys_role:permission:list')") public ApiResponse> listRolePermissions(@PathVariable Long id) { List rows = sysRolePermissionMapper.selectList( new QueryWrapper().eq("role_id", id) @@ -63,6 +70,7 @@ public class RoleController { } @PostMapping("/{id}/permissions") + @PreAuthorize("@ss.hasPermi('sys_role:permission:save')") public ApiResponse saveRolePermissions(@PathVariable Long id, @RequestBody PermissionBindingPayload payload) { List permIds = payload == null ? null : payload.getPermIds(); sysRolePermissionMapper.delete(new QueryWrapper().eq("role_id", id)); diff --git a/backend/src/main/java/com/imeeting/controller/SysParamController.java b/backend/src/main/java/com/imeeting/controller/SysParamController.java index d4ce1c7..e5e6841 100644 --- a/backend/src/main/java/com/imeeting/controller/SysParamController.java +++ b/backend/src/main/java/com/imeeting/controller/SysParamController.java @@ -3,6 +3,7 @@ package com.imeeting.controller; import com.imeeting.common.ApiResponse; import com.imeeting.entity.SysParam; import com.imeeting.service.SysParamService; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -17,16 +18,19 @@ public class SysParamController { } @GetMapping + @PreAuthorize("@ss.hasPermi('sys_param:list')") public ApiResponse> list() { return ApiResponse.ok(sysParamService.list()); } @GetMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_param:query')") public ApiResponse get(@PathVariable Long id) { return ApiResponse.ok(sysParamService.getById(id)); } @PostMapping + @PreAuthorize("@ss.hasPermi('sys_param:create')") public ApiResponse create(@RequestBody SysParam param) { boolean saved = sysParamService.save(param); if (saved) { @@ -36,6 +40,7 @@ public class SysParamController { } @PutMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_param:update')") public ApiResponse update(@PathVariable Long id, @RequestBody SysParam param) { param.setParamId(id); boolean updated = sysParamService.updateById(param); @@ -46,6 +51,7 @@ public class SysParamController { } @DeleteMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_param:delete')") public ApiResponse delete(@PathVariable Long id) { SysParam param = sysParamService.getById(id); boolean removed = sysParamService.removeById(id); diff --git a/backend/src/main/java/com/imeeting/controller/UserController.java b/backend/src/main/java/com/imeeting/controller/UserController.java index 8aa82b6..16da093 100644 --- a/backend/src/main/java/com/imeeting/controller/UserController.java +++ b/backend/src/main/java/com/imeeting/controller/UserController.java @@ -3,12 +3,16 @@ package com.imeeting.controller; import com.imeeting.auth.JwtTokenProvider; import com.imeeting.common.ApiResponse; import com.imeeting.dto.UserProfile; +import com.imeeting.security.LoginUser; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.imeeting.entity.SysUser; import com.imeeting.entity.SysUserRole; import com.imeeting.mapper.SysUserRoleMapper; import com.imeeting.service.SysUserService; import io.jsonwebtoken.Claims; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; @@ -31,16 +35,20 @@ public class UserController { } @GetMapping + @PreAuthorize("@ss.hasPermi('sys_user:list')") public ApiResponse> list() { return ApiResponse.ok(sysUserService.list()); } @GetMapping("/me") - public ApiResponse me(@RequestHeader("Authorization") String authorization) { - Long userId = resolveUserId(authorization); - if (userId == null) { + public ApiResponse me() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null || !(authentication.getPrincipal() instanceof LoginUser)) { return ApiResponse.error("Unauthorized"); } + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + Long userId = loginUser.getUserId(); + SysUser user = sysUserService.getById(userId); if (user == null) { return ApiResponse.error("User not found"); @@ -57,11 +65,13 @@ public class UserController { } @GetMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_user:query')") public ApiResponse get(@PathVariable Long id) { return ApiResponse.ok(sysUserService.getById(id)); } @PostMapping + @PreAuthorize("@ss.hasPermi('sys_user:create')") public ApiResponse create(@RequestBody SysUser user) { if (user.getPasswordHash() != null && !user.getPasswordHash().isEmpty()) { user.setPasswordHash(passwordEncoder.encode(user.getPasswordHash())); @@ -70,6 +80,7 @@ public class UserController { } @PutMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_user:update')") public ApiResponse update(@PathVariable Long id, @RequestBody SysUser user) { user.setUserId(id); if (user.getPasswordHash() != null && !user.getPasswordHash().isEmpty()) { @@ -79,11 +90,13 @@ public class UserController { } @DeleteMapping("/{id}") + @PreAuthorize("@ss.hasPermi('sys_user:delete')") public ApiResponse delete(@PathVariable Long id) { return ApiResponse.ok(sysUserService.removeById(id)); } @GetMapping("/{id}/roles") + @PreAuthorize("@ss.hasPermi('sys_user:role:list')") public ApiResponse> listUserRoles(@PathVariable Long id) { List rows = sysUserRoleMapper.selectList( new QueryWrapper().eq("user_id", id) @@ -98,6 +111,7 @@ public class UserController { } @PostMapping("/{id}/roles") + @PreAuthorize("@ss.hasPermi('sys_user:role:save')") public ApiResponse saveUserRoles(@PathVariable Long id, @RequestBody RoleBindingPayload payload) { List roleIds = payload == null ? null : payload.getRoleIds(); sysUserRoleMapper.delete(new QueryWrapper().eq("user_id", id)); diff --git a/backend/src/main/java/com/imeeting/service/SysPermissionService.java b/backend/src/main/java/com/imeeting/service/SysPermissionService.java index f4064eb..21320ed 100644 --- a/backend/src/main/java/com/imeeting/service/SysPermissionService.java +++ b/backend/src/main/java/com/imeeting/service/SysPermissionService.java @@ -4,7 +4,10 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.imeeting.entity.SysPermission; import java.util.List; +import java.util.Set; public interface SysPermissionService extends IService { List listByUserId(Long userId); + + Set listPermissionCodesByUserId(Long userId); } diff --git a/backend/src/main/java/com/imeeting/service/impl/SysPermissionServiceImpl.java b/backend/src/main/java/com/imeeting/service/impl/SysPermissionServiceImpl.java index 17aad13..d5d00a4 100644 --- a/backend/src/main/java/com/imeeting/service/impl/SysPermissionServiceImpl.java +++ b/backend/src/main/java/com/imeeting/service/impl/SysPermissionServiceImpl.java @@ -7,6 +7,8 @@ import com.imeeting.service.SysPermissionService; import org.springframework.stereotype.Service; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; @Service public class SysPermissionServiceImpl extends ServiceImpl implements SysPermissionService { @@ -15,9 +17,18 @@ public class SysPermissionServiceImpl extends ServiceImpl listPermissionCodesByUserId(Long userId) { + List perms = listByUserId(userId); + return perms.stream() + .map(SysPermission::getCode) + .filter(code -> code != null && !code.isEmpty()) + .collect(Collectors.toSet()); + } }