From 0ca2a5317b628680d11a27927c13bea43d33a39a Mon Sep 17 00:00:00 2001 From: bruce Date: Thu, 13 Feb 2025 16:54:37 +0800 Subject: [PATCH] =?UTF-8?q?v0.1.5=20=E4=BC=98=E5=8C=96TokenUtil=20?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E7=94=A8=E6=88=B7=E6=93=8D=E4=BD=9C=E9=83=A8?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/bruce/sams/config/SecurityConfig.java | 4 +- .../bruce/sams/controller/UserController.java | 67 ++++++++++ .../controller/UserProfileController.java | 38 ++++++ .../com/bruce/sams/filters/JwtAuthFilter.java | 14 +- .../com/bruce/sams/service/UserService.java | 55 ++++++++ .../sams/service/impl/AuthServiceImpl.java | 6 +- .../sams/service/impl/UserServiceImpl.java | 122 ++++++++++++++++++ .../java/com/bruce/sams/utils/TokenUtil.java | 22 +++- 8 files changed, 309 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/bruce/sams/controller/UserController.java create mode 100644 src/main/java/com/bruce/sams/controller/UserProfileController.java create mode 100644 src/main/java/com/bruce/sams/service/UserService.java create mode 100644 src/main/java/com/bruce/sams/service/impl/UserServiceImpl.java diff --git a/src/main/java/com/bruce/sams/config/SecurityConfig.java b/src/main/java/com/bruce/sams/config/SecurityConfig.java index 8395b194..763fe15f 100644 --- a/src/main/java/com/bruce/sams/config/SecurityConfig.java +++ b/src/main/java/com/bruce/sams/config/SecurityConfig.java @@ -21,8 +21,8 @@ public class SecurityConfig { .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/login").permitAll() - .requestMatchers("/admin/**").hasAuthority("leader") - .requestMatchers("/user/**").hasAuthority("participant") + .requestMatchers("/api/admin/**").hasAuthority("leader") + .requestMatchers("/api/user/**").hasAuthority("participant") .anyRequest().authenticated() ) .addFilterBefore(new JwtAuthFilter(), UsernamePasswordAuthenticationFilter.class); diff --git a/src/main/java/com/bruce/sams/controller/UserController.java b/src/main/java/com/bruce/sams/controller/UserController.java new file mode 100644 index 00000000..6f08f367 --- /dev/null +++ b/src/main/java/com/bruce/sams/controller/UserController.java @@ -0,0 +1,67 @@ +package com.bruce.sams.controller; + +import com.bruce.sams.domain.sys.User; +import com.bruce.sams.utils.AjaxResult; +import com.bruce.sams.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 用户管理控制器(仅管理员可用) + */ +@RestController +@RequestMapping("/api/admin/user") +public class UserController { + + @Autowired + private UserService userService; + + /** + * 批量导入用户 + * + * @param users 用户列表 + * @return 操作结果 + */ + @PostMapping("/import") + public AjaxResult importUsers(@RequestBody List users) { + userService.importUsers(users); + return AjaxResult.success("用户导入成功"); + } + + /** + * 查询用户列表(可按学号、用户名、邮箱搜索) + * + * @param keyword 关键字(可选) + * @return 用户列表 + */ + @GetMapping("/list") + public AjaxResult listUsers(@RequestParam(required = false) String keyword) { + return AjaxResult.success("查询成功", userService.listUsers(keyword)); + } + + /** + * 更新用户信息(角色、状态、密码) + * + * @param user 用户对象 + * @return 操作结果 + */ + @PutMapping("/update") + public AjaxResult updateUser(@RequestBody User user) { + userService.updateUser(user); + return AjaxResult.success("用户信息更新成功"); + } + + /** + * 删除用户(逻辑删除) + * + * @param userId 用户ID + * @return 操作结果 + */ + @DeleteMapping("/delete/{userId}") + public AjaxResult deleteUser(@PathVariable Long userId) { + userService.deleteUser(userId); + return AjaxResult.success("用户删除成功"); + } +} diff --git a/src/main/java/com/bruce/sams/controller/UserProfileController.java b/src/main/java/com/bruce/sams/controller/UserProfileController.java new file mode 100644 index 00000000..77b53c83 --- /dev/null +++ b/src/main/java/com/bruce/sams/controller/UserProfileController.java @@ -0,0 +1,38 @@ +package com.bruce.sams.controller; + +import com.bruce.sams.domain.sys.User; +import com.bruce.sams.utils.AjaxResult; +import com.bruce.sams.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * 普通用户修改个人信息控制器 + */ +@RestController +@RequestMapping("/api/user/profile") +public class UserProfileController { + + @Autowired + private UserService userService; + + /** + * 修改密码 + */ + @PutMapping("/change-password") + public AjaxResult changePassword(@RequestAttribute Long userId, + @RequestParam String oldPassword, + @RequestParam String newPassword) { + userService.changePassword(userId, oldPassword, newPassword); + return AjaxResult.success("密码修改成功"); + } + + /** + * 修改个人信息 + */ + @PutMapping("/update") + public AjaxResult updateProfile(@RequestAttribute Long userId, @RequestBody User user) { + userService.updateProfile(userId, user); + return AjaxResult.success("个人信息更新成功"); + } +} diff --git a/src/main/java/com/bruce/sams/filters/JwtAuthFilter.java b/src/main/java/com/bruce/sams/filters/JwtAuthFilter.java index 4a14173f..4090bbfa 100644 --- a/src/main/java/com/bruce/sams/filters/JwtAuthFilter.java +++ b/src/main/java/com/bruce/sams/filters/JwtAuthFilter.java @@ -22,27 +22,25 @@ public class JwtAuthFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - // 获取请求头中的 Authorization 令牌 String token = request.getHeader("Authorization"); - // 判断令牌是否存在且以 "Bearer " 开头 if (token != null && token.startsWith("Bearer ")) { - token = token.substring(7); // 去掉 "Bearer " 前缀 + token = token.substring(7); try { - // 解析 JWT 令牌 - String schoolId = TokenUtil.getSubjectFromToken(token); + Long userId = TokenUtil.getUserIdFromToken(token); String role = TokenUtil.getRoleFromToken(token); - // 设置认证信息 + // 将 userId 存入 request,供 Controller 直接使用 + request.setAttribute("userId", userId); + SecurityContextHolder.getContext().setAuthentication( - new UsernamePasswordAuthenticationToken(schoolId, null, null)); + new UsernamePasswordAuthenticationToken(userId, null, null)); } catch (Exception e) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid Token"); return; } } - // 继续执行过滤器链 filterChain.doFilter(request, response); } } diff --git a/src/main/java/com/bruce/sams/service/UserService.java b/src/main/java/com/bruce/sams/service/UserService.java new file mode 100644 index 00000000..90fad651 --- /dev/null +++ b/src/main/java/com/bruce/sams/service/UserService.java @@ -0,0 +1,55 @@ +package com.bruce.sams.service; + +import com.bruce.sams.domain.sys.User; + +import java.util.List; + +public interface UserService { + + /** + * 批量导入用户 + * + * @param users 用户列表 + */ + void importUsers(List users); + + /** + * 查询用户列表(学号、用户名、邮箱) + * + * @param keyword 关键字 + * @return 用户列表 + */ + List listUsers(String keyword); + + /** + * 更新用户信息(角色、状态、密码) + * + * @param user 用户对象 + */ + void updateUser(User user); + + /** + * 用户修改密码 + * + * @param userId 用户ID + * @param oldPassword 旧密码 + * @param newPassword 新密码 + */ + void changePassword(Long userId, String oldPassword, String newPassword); + + /** + * 用户修改个人信息(昵称、邮箱、头像) + * + * @param userId 用户ID(从 JWT 获取) + * @param updatedUser 用户提交的新信息(昵称、邮箱、头像) + */ + void updateProfile(Long userId, User updatedUser); + + /** + * 删除用户 + * + * @param userId 用户ID + */ + void deleteUser(Long userId); + +} diff --git a/src/main/java/com/bruce/sams/service/impl/AuthServiceImpl.java b/src/main/java/com/bruce/sams/service/impl/AuthServiceImpl.java index 9f2babc8..9f29d2fb 100644 --- a/src/main/java/com/bruce/sams/service/impl/AuthServiceImpl.java +++ b/src/main/java/com/bruce/sams/service/impl/AuthServiceImpl.java @@ -1,15 +1,15 @@ package com.bruce.sams.service.impl; import com.bruce.sams.domain.entity.LoginRequest; +import com.bruce.sams.domain.sys.User; import com.bruce.sams.exception.AccountDisabledException; import com.bruce.sams.exception.PasswordIncorrectException; import com.bruce.sams.exception.UserNotFoundException; import com.bruce.sams.mapper.SysRoleMapper; import com.bruce.sams.mapper.SysUserMapper; -import com.bruce.sams.domain.sys.User; +import com.bruce.sams.service.AuthService; import com.bruce.sams.utils.PasswordUtil; import com.bruce.sams.utils.TokenUtil; -import com.bruce.sams.service.AuthService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -62,6 +62,6 @@ public class AuthServiceImpl implements AuthService { String role = roleMapper.findByRoleId(user.getRoleId()).getRoleKey(); // 生成 JWT 令牌 - return TokenUtil.generateToken(user.getSchoolId(), role); + return TokenUtil.generateToken(user); } } diff --git a/src/main/java/com/bruce/sams/service/impl/UserServiceImpl.java b/src/main/java/com/bruce/sams/service/impl/UserServiceImpl.java new file mode 100644 index 00000000..25d8e98e --- /dev/null +++ b/src/main/java/com/bruce/sams/service/impl/UserServiceImpl.java @@ -0,0 +1,122 @@ +package com.bruce.sams.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bruce.sams.domain.sys.User; +import com.bruce.sams.exception.PasswordIncorrectException; +import com.bruce.sams.exception.UserNotFoundException; +import com.bruce.sams.mapper.SysUserMapper; +import com.bruce.sams.service.UserService; +import com.bruce.sams.utils.PasswordUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UserServiceImpl extends ServiceImpl + implements UserService { + + @Autowired + private SysUserMapper userMapper; + + /** + * 批量导入用户 + * + * @param users 用户列表 + */ + public void importUsers(List users) { + for (User user : users) { + // 加密用户密码(默认密码123456) + if (user.getPassword() == null || user.getPassword().isEmpty()) { + user.setPassword(PasswordUtil.encode("123456")); // 默认密码 + } else { + user.setPassword(PasswordUtil.encode(user.getPassword())); + } + userMapper.insert(user); + } + } + + /** + * 查询用户列表(学号、用户名、邮箱) + * + * @param keyword 关键字 + * @return 用户列表 + */ + public List listUsers(String keyword) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if (keyword != null && !keyword.isEmpty()) { + queryWrapper.like(User::getUserName, keyword) + .or().like(User::getSchoolId, keyword) + .or().like(User::getEmail, keyword); + } + return userMapper.selectList(queryWrapper); + } + + /** + * 更新用户信息(角色、状态、密码) + * + * @param user 用户对象 + */ + public void updateUser(User user) { + // 如果要修改密码,先加密 + if (user.getPassword() != null && !user.getPassword().isEmpty()) { + user.setPassword(PasswordUtil.encode(user.getPassword())); + } + userMapper.updateById(user); + } + + + /** + * 用户修改密码 + * + * @param userId 用户ID + * @param oldPassword 旧密码 + * @param newPassword 新密码 + */ + public void changePassword(Long userId, String oldPassword, String newPassword) { + // 获取用户 + User user = userMapper.selectById(userId); + if (user == null) { + throw new UserNotFoundException(); + } + + // 验证旧密码 + if (!PasswordUtil.matches(oldPassword, user.getPassword())) { + throw new PasswordIncorrectException(); + } + + // 更新新密码(加密存储) + user.setPassword(PasswordUtil.encode(newPassword)); + userMapper.updateById(user); + } + + /** + * 用户修改个人信息(昵称、邮箱、头像) + * + * @param userId 用户ID(从 JWT 获取) + * @param updatedUser 用户提交的新信息(昵称、邮箱、头像) + */ + public void updateProfile(Long userId, User updatedUser) { + User user = userMapper.selectById(userId); + if (user == null) { + throw new UserNotFoundException(); + } + + // 仅允许修改部分字段 + user.setNickName(updatedUser.getNickName()); + user.setEmail(updatedUser.getEmail()); + user.setAvatar(updatedUser.getAvatar()); + + userMapper.updateById(user); + } + + /** + * 删除用户 + * + * @param userId 用户ID + */ + public void deleteUser(Long userId) { + userMapper.deleteById(userId); + } +} diff --git a/src/main/java/com/bruce/sams/utils/TokenUtil.java b/src/main/java/com/bruce/sams/utils/TokenUtil.java index 82d81f42..ffa76d2a 100644 --- a/src/main/java/com/bruce/sams/utils/TokenUtil.java +++ b/src/main/java/com/bruce/sams/utils/TokenUtil.java @@ -1,5 +1,6 @@ package com.bruce.sams.utils; +import com.bruce.sams.domain.sys.User; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; @@ -23,15 +24,14 @@ public class TokenUtil { /** * 生成JWT令牌 * - * @param username 需要包含的声明 - * @param role 令牌主体 + * @param user 用户信息 * @return 生成的JWT字符串 */ - public static String generateToken(String username , String role) { + public static String generateToken(User user) { HashMap claims = new HashMap<>(); - claims.put("role", role); + claims.put("role", user.getRoleId()); return Jwts.builder() - .subject(username) + .subject(String.valueOf(user.getUserId())) .claims(claims) .issuedAt(new Date()) .expiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) @@ -54,7 +54,7 @@ public class TokenUtil { } /** - * 从令牌中获取用户名 + * 从令牌中获取token主体 * * @param token JWT字符串 * @return 令牌中的subject @@ -63,6 +63,16 @@ public class TokenUtil { return parseToken(token).getSubject(); } + /** + * 从令牌中获取用户ID + * + * @param token JWT字符串 + * @return 令牌中的用户ID + */ + public static Long getUserIdFromToken(String token) { + return Long.parseLong(getSubjectFromToken(token)); + } + /** * 从令牌中获取角色信息 *