feat(security): 实现JWT认证与授权功能
重构用户登录服务,引入Spring Security和JWT认证机制 - 新增JwtUtils工具类处理JWT生成与验证 - 添加JwtAuthenticationFilter拦截请求验证token - 实现UserDetailsService从数据库加载用户信息 - 创建AuthController处理登录请求返回JWT - 重构用户角色权限相关接口,支持基于角色的访问控制 - 移除旧的安全配置,启用新的SecurityConfig - 新增LoginResponse DTO替代旧的LoginUser - 优化用户密码加密存储,使用BCryptPasswordEncoder
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package com.qf.backend.config;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import com.qf.backend.util.JwtUtils;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* JWT认证过滤器,用于解析和验证JWT
|
||||
* 拦截所有请求,检查Authorization头中的Bearer token
|
||||
*/
|
||||
@Component
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
|
||||
|
||||
@Autowired
|
||||
private JwtUtils jwtUtils;
|
||||
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
/**
|
||||
* 过滤请求,检查JWT并设置认证信息
|
||||
*/
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
try {
|
||||
// 1. 从请求头中获取Authorization
|
||||
String authorizationHeader = request.getHeader("Authorization");
|
||||
String token = null;
|
||||
String username = null;
|
||||
|
||||
// 2. 检查Authorization头格式
|
||||
if (authorizationHeader != null && authorizationHeader.startsWith(jwtUtils.getTokenPrefix() + " ")) {
|
||||
token = authorizationHeader.substring(jwtUtils.getTokenPrefix().length() + 1);
|
||||
username = jwtUtils.getUsernameFromToken(token);
|
||||
}
|
||||
|
||||
// 3. 如果token有效且用户未认证,设置认证信息
|
||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
|
||||
|
||||
// 4. 验证token
|
||||
if (jwtUtils.validateToken(token, userDetails)) {
|
||||
// 5. 创建认证对象
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
||||
userDetails, null, userDetails.getAuthorities());
|
||||
|
||||
// 6. 设置认证细节
|
||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
|
||||
// 7. 设置认证信息到SecurityContext
|
||||
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("JWT认证失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 8. 继续过滤链
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,6 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.qf.backend.entity.Roles;
|
||||
import com.qf.backend.service.RolesService;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
/**
|
||||
* 角色初始化配置类,用于在系统启动时创建内置角色
|
||||
* @author 30803
|
||||
@@ -21,19 +19,18 @@ public class RoleInitializer {
|
||||
|
||||
@Autowired
|
||||
private RolesService rolesService;
|
||||
|
||||
/**
|
||||
* 系统启动时初始化内置角色
|
||||
*/
|
||||
@PostConstruct
|
||||
// @PostConstruct
|
||||
public void initRoles() {
|
||||
logger.info("开始初始化内置角色...");
|
||||
|
||||
// 定义内置角色信息
|
||||
String[][] roleInfos = {
|
||||
{"用户", "默认用户角色", "0"}, // roleType: 0-默认用户
|
||||
{"店主", "店铺管理员角色", "1"}, // roleType: 1-店主
|
||||
{"管理员", "系统管理员角色", "2"} // roleType: 2-管理员
|
||||
{"User", "默认用户角色", "0"}, // roleType: 0-默认用户
|
||||
{"Shopkeeper", "店铺管理员角色", "1"}, // roleType: 1-店主
|
||||
{"Admin", "系统管理员角色", "2"} // roleType: 2-管理员
|
||||
};
|
||||
|
||||
for (String[] roleInfo : roleInfos) {
|
||||
|
||||
@@ -1,57 +1,114 @@
|
||||
// /*
|
||||
// * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
// * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
// */
|
||||
// package com.qf.backend.config;
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
*/
|
||||
package com.qf.backend.config;
|
||||
|
||||
// import org.springframework.context.annotation.Bean;
|
||||
// import org.springframework.context.annotation.Configuration;
|
||||
// import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
// import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
// import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
// import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
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;
|
||||
|
||||
// /**
|
||||
// * 安全配置类(仅开发 禁用安全认证)
|
||||
// *
|
||||
// * @author 30803
|
||||
// */
|
||||
// @Configuration
|
||||
// @EnableWebSecurity
|
||||
// public class SecurityConfig {
|
||||
/**
|
||||
* 安全配置类,使用JWT认证
|
||||
* 该类是Spring Security的核心配置类,负责配置安全策略、认证机制和授权规则
|
||||
* 与AuthController.java的关系:
|
||||
* 1. AuthController处理登录请求,调用AuthenticationManager进行认证
|
||||
* 2. SecurityConfig配置AuthenticationManager和相关组件
|
||||
* 3. SecurityConfig配置JWT过滤器,用于拦截后续请求并验证JWT
|
||||
* 4. 两者协同工作,完成完整的认证授权流程
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity // 启用Spring Security
|
||||
public class SecurityConfig {
|
||||
|
||||
// @Bean
|
||||
// public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// http
|
||||
// .authorizeHttpRequests(auth -> auth
|
||||
// .requestMatchers("/users/**").permitAll() // 公开路径
|
||||
// .requestMatchers("/admin/**").hasRole("ADMIN") // 需要 ADMIN 角色
|
||||
// .anyRequest().authenticated() // 其他请求需登录
|
||||
// )
|
||||
// .formLogin(form -> form
|
||||
// .loginPage("/login") // 自定义登录页(可选)
|
||||
// .permitAll()
|
||||
// )
|
||||
// .logout(logout -> logout
|
||||
// .permitAll()
|
||||
// );
|
||||
// return http.build();
|
||||
// }
|
||||
/**
|
||||
* 注入JWT认证过滤器
|
||||
* 该过滤器会拦截所有请求,检查Authorization头中的Bearer token
|
||||
*/
|
||||
@Autowired
|
||||
private JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||
|
||||
// @Bean
|
||||
// public UserDetailsService userDetailsService() {
|
||||
// UserDetails user = User.withDefaultPasswordEncoder()
|
||||
// .username("user")
|
||||
// .password("123456")
|
||||
// .roles("USER")
|
||||
// .build();
|
||||
/**
|
||||
* 配置SecurityFilterChain
|
||||
* SecurityFilterChain是Spring Security 3.x的新特性,替代了旧版的WebSecurityConfigurerAdapter
|
||||
* 该方法配置了安全策略,包括:
|
||||
* 1. 禁用CSRF保护(适合API服务,因为API通常使用JWT而不是Session)
|
||||
* 2. 配置会话管理为无状态(适合RESTful API,不使用Session)
|
||||
* 3. 配置请求授权规则
|
||||
* 4. 禁用默认的登录和注销功能(使用自定义的AuthController)
|
||||
* 5. 添加JWT过滤器
|
||||
*
|
||||
* @param http HttpSecurity对象,用于配置安全策略
|
||||
* @return SecurityFilterChain对象
|
||||
* @throws Exception 配置过程中可能抛出的异常
|
||||
*/
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// 1. 禁用CSRF保护
|
||||
// CSRF(跨站请求伪造)保护主要用于Web应用,防止第三方网站伪造请求
|
||||
// API服务通常使用JWT认证,不需要CSRF保护
|
||||
.csrf(csrf -> csrf.disable())
|
||||
|
||||
// UserDetails admin = User.withDefaultPasswordEncoder()
|
||||
// .username("admin")
|
||||
// .password("admin123")
|
||||
// .roles("USER", "ADMIN")
|
||||
// .build();
|
||||
// 2. 配置会话管理:无状态
|
||||
// 无状态意味着服务器不存储用户会话信息,每个请求都需要携带完整的认证信息
|
||||
// 这是RESTful API的最佳实践,提高了系统的可扩展性和安全性
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
|
||||
// return new InMemoryUserDetailsManager(user, admin);
|
||||
// }
|
||||
// }
|
||||
// 3. 配置请求授权规则
|
||||
// 使用Lambda DSL配置请求匹配规则和授权要求
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
// 登录接口公开访问,不需要认证
|
||||
.requestMatchers("/api/auth/login").permitAll()
|
||||
// 其他所有请求都需要认证
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
|
||||
// 4. 禁用默认的登录和注销功能
|
||||
// 因为我们使用自定义的AuthController处理登录请求
|
||||
.formLogin(form -> form.disable())
|
||||
.logout(logout -> logout.disable());
|
||||
|
||||
// 5. 添加JWT过滤器
|
||||
// 在UsernamePasswordAuthenticationFilter之前添加JWT过滤器
|
||||
// 这样所有请求都会先经过JWT过滤器,验证token的有效性
|
||||
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置PasswordEncoder
|
||||
* PasswordEncoder用于加密和验证密码
|
||||
* BCryptPasswordEncoder是Spring Security推荐的密码编码器,使用随机盐值
|
||||
*
|
||||
* @return PasswordEncoder对象
|
||||
*/
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置AuthenticationManager
|
||||
* AuthenticationManager是Spring Security的核心组件,负责处理认证请求
|
||||
* 该方法从AuthenticationConfiguration中获取AuthenticationManager实例
|
||||
*
|
||||
* @param authenticationConfiguration AuthenticationConfiguration对象
|
||||
* @return AuthenticationManager对象
|
||||
* @throws Exception 配置过程中可能抛出的异常
|
||||
*/
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
|
||||
return authenticationConfiguration.getAuthenticationManager();
|
||||
}
|
||||
}
|
||||
|
||||
69
src/main/java/com/qf/backend/config/UserInitializer.java
Normal file
69
src/main/java/com/qf/backend/config/UserInitializer.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package com.qf.backend.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.qf.backend.entity.Users;
|
||||
import com.qf.backend.service.UsersService;
|
||||
import com.qf.backend.util.ValidateUtil;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
/**
|
||||
* 用户初始化配置类,用于在系统启动时创建内置用户
|
||||
* @author 30803
|
||||
*/
|
||||
@Component
|
||||
public class UserInitializer {
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserInitializer.class);
|
||||
|
||||
@Autowired
|
||||
private UsersService usersService;
|
||||
|
||||
/**
|
||||
* 系统启动时初始化内置用户
|
||||
*/
|
||||
// @PostConstruct
|
||||
public void initUsers() {
|
||||
logger.info("开始初始化内置用户...");
|
||||
|
||||
// 定义内置用户信息
|
||||
String[][] userInfos = {
|
||||
// 用户名,密码,手机号,邮箱,状态
|
||||
{"admin", "admin123", "13800000000", "admin@qq.com", "1"}, // 管理员用户
|
||||
{"shopkeeper", "123456", "13800000001", "shopkeeper@qq.com", "1"}, // 店主用户
|
||||
{"user", "123456", "13800000002", "user@qq.com", "1"} // 普通用户
|
||||
};
|
||||
|
||||
for (String[] userInfo : userInfos) {
|
||||
String username = userInfo[0];
|
||||
String password = userInfo[1];
|
||||
String phone = userInfo[2];
|
||||
String email = userInfo[3];
|
||||
Integer status = Integer.parseInt(userInfo[4]);
|
||||
|
||||
// 检查用户是否已存在
|
||||
Users existingUser = usersService.getOne(new QueryWrapper<Users>().eq("username", username));
|
||||
if (existingUser == null) {
|
||||
// 创建新用户
|
||||
Users user = new Users();
|
||||
user.setUsername(username);
|
||||
user.setPassword(password);
|
||||
user.setPhone(phone);
|
||||
user.setEmail(email);
|
||||
user.setStatus(status);
|
||||
// 注意:不设置last_login_time字段,因为数据库中可能不存在该字段
|
||||
|
||||
usersService.createUser(user);
|
||||
logger.info("成功创建内置用户: {}", username);
|
||||
} else {
|
||||
logger.info("内置用户 {} 已存在,跳过创建", username);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("内置用户初始化完成");
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// /*
|
||||
// * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
// * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
// */
|
||||
|
||||
// package com.qf.backend.config;
|
||||
|
||||
// import org.springframework.beans.factory.annotation.Autowired;
|
||||
// import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
// import org.springframework.stereotype.Component;
|
||||
// import org.springframework.stereotype.Service;
|
||||
// import org.springframework.security.core.userdetails.UserDetails;
|
||||
// import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
// import org.springframework.security.core.authority.AuthorityUtils;
|
||||
// import com.qf.backend.mapper.UsersMapper;
|
||||
// import com.qf.backend.entity.Users;
|
||||
// import com.qf.backend.mapper.RolesMapper;
|
||||
|
||||
|
||||
|
||||
// /**
|
||||
// * 自定义UserDetailsService
|
||||
// * 用于从数据库加载用户信息进行认证
|
||||
// * @author 30803
|
||||
// */
|
||||
// @Component
|
||||
// public class UsersDetailsServiceConfig implements UserDetailsService {
|
||||
// @Autowired
|
||||
// private UsersMapper usersMapper;
|
||||
// @Autowired
|
||||
// private RolesMapper rolesMapper;
|
||||
|
||||
|
||||
// @Override
|
||||
// public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
// Users users = usersMapper.selectByUsername(username);
|
||||
// if (users == null) {
|
||||
// throw new UsernameNotFoundException("用户不存在"+username);
|
||||
// }
|
||||
// int roleType = rolesMapper.selectById(users.getId()).getRoleType();
|
||||
// }
|
||||
|
||||
// }
|
||||
89
src/main/java/com/qf/backend/controller/AuthController.java
Normal file
89
src/main/java/com/qf/backend/controller/AuthController.java
Normal file
@@ -0,0 +1,89 @@
|
||||
package com.qf.backend.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
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 com.qf.backend.dto.LoginRequest;
|
||||
import com.qf.backend.dto.LoginResponse;
|
||||
import com.qf.backend.util.JwtUtils;
|
||||
|
||||
/**
|
||||
* 认证控制器,用于处理用户登录请求
|
||||
* 该控制器接收前端发送的用户名和密码,通过Spring Security进行认证,认证成功后生成JWT返回给前端
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
public class AuthController {
|
||||
|
||||
/**
|
||||
* 注入AuthenticationManager,用于处理认证请求
|
||||
* AuthenticationManager是Spring Security的核心组件,负责协调认证过程
|
||||
*/
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
/**
|
||||
* 注入JWT工具类,用于生成和验证JWT
|
||||
*/
|
||||
@Autowired
|
||||
private JwtUtils jwtUtils;
|
||||
|
||||
/**
|
||||
* 用户登录接口
|
||||
* @param loginRequest 登录请求体,包含用户名和密码
|
||||
* @return ResponseEntity 包含JWT令牌的响应
|
||||
*
|
||||
* 登录流程:
|
||||
* 1. 前端发送POST请求到/api/auth/login,携带用户名和密码
|
||||
* 2. 该方法被调用,创建UsernamePasswordAuthenticationToken对象
|
||||
* 3. 调用AuthenticationManager.authenticate()方法进行认证
|
||||
* 4. 认证成功后,从Authentication对象中获取UserDetails
|
||||
* 5. 使用JwtUtils生成JWT令牌
|
||||
* 6. 返回包含JWT令牌的响应
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest loginRequest) {
|
||||
try {
|
||||
// 1. 创建认证令牌,将用户名和密码封装到UsernamePasswordAuthenticationToken中
|
||||
// 这里的令牌是未认证状态的,因为还没有验证密码是否正确
|
||||
UsernamePasswordAuthenticationToken authenticationToken =
|
||||
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
|
||||
|
||||
// 2. 调用AuthenticationManager.authenticate()方法进行认证
|
||||
// 这个方法会触发以下流程:
|
||||
// a. 调用UserDetailsService.loadUserByUsername()方法,从数据库加载用户信息
|
||||
// b. 使用PasswordEncoder验证密码是否匹配
|
||||
// c. 认证成功后,返回一个已认证的Authentication对象
|
||||
Authentication authentication = authenticationManager.authenticate(authenticationToken);
|
||||
|
||||
// 3. 从已认证的Authentication对象中获取UserDetails
|
||||
// UserDetails包含了用户的基本信息和权限列表
|
||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||
|
||||
// 4. 使用JwtUtils生成JWT令牌
|
||||
// 令牌中包含了用户名、权限等信息,以及过期时间
|
||||
String jwt = jwtUtils.generateToken(userDetails);
|
||||
|
||||
// 5. 创建LoginResponse对象,封装JWT令牌和令牌类型
|
||||
LoginResponse loginResponse = new LoginResponse();
|
||||
loginResponse.setToken(jwt);
|
||||
loginResponse.setTokenType(jwtUtils.getTokenPrefix());
|
||||
// 5. 返回包含JWT令牌的响应
|
||||
// 响应格式为:{"token": "xxx", "tokenType": "Bearer"}
|
||||
return ResponseEntity.ok(loginResponse);
|
||||
} catch (BadCredentialsException e) {
|
||||
// 认证失败,通常是用户名不存在或密码错误
|
||||
// 返回401 Unauthorized响应
|
||||
return ResponseEntity.status(401).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
*/
|
||||
|
||||
package com.qf.backend.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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 com.qf.backend.common.Result;
|
||||
import com.qf.backend.dto.LoginRequest;
|
||||
import com.qf.backend.dto.LoginUser;
|
||||
import com.qf.backend.service.UserLoginService;
|
||||
/**
|
||||
*
|
||||
* @author 30803
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/login")
|
||||
public class LoginController {
|
||||
@Autowired
|
||||
private UserLoginService userLoginService;
|
||||
|
||||
@PostMapping("/login")
|
||||
public Result<LoginUser> login(@RequestBody LoginRequest loginRequest) {
|
||||
return userLoginService.login(loginRequest.getUsername(), loginRequest.getPassword());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
*/
|
||||
|
||||
package com.qf.backend.controller;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
import com.qf.backend.common.Result;
|
||||
import com.qf.backend.entity.Permissions;
|
||||
import com.qf.backend.service.PermissionsService;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 权限管理控制器
|
||||
* 处理权限相关的HTTP请求
|
||||
* 遵循RESTful API设计规范
|
||||
* @author 30803
|
||||
*/
|
||||
@RequestMapping("/api/permissions")
|
||||
@RestController
|
||||
public class PermissionsController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(PermissionsController.class);
|
||||
|
||||
@Autowired
|
||||
private PermissionsService permissionsService;
|
||||
|
||||
/**
|
||||
* 查询所有权限
|
||||
* @return 权限列表
|
||||
*/
|
||||
@GetMapping
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<List<Permissions>> listAllPermissions() {
|
||||
logger.info("管理员查询所有权限");
|
||||
return permissionsService.listAllPermissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据权限ID查询权限
|
||||
* @param id 权限ID
|
||||
* @return 权限信息
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Permissions> getPermissionById(@PathVariable Long id) {
|
||||
logger.info("管理员根据ID查询权限,ID:{}", id);
|
||||
return permissionsService.getPermissionById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据权限编码查询权限
|
||||
* @param permissionCode 权限编码
|
||||
* @return 权限信息
|
||||
*/
|
||||
@GetMapping("/code/{permissionCode}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Permissions> getPermissionByCode(@PathVariable String permissionCode) {
|
||||
logger.info("管理员根据权限编码查询权限,权限编码:{}", permissionCode);
|
||||
return permissionsService.getPermissionByCode(permissionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建权限
|
||||
* @param permissions 权限信息
|
||||
* @return 是否成功
|
||||
*/
|
||||
@PostMapping
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> createPermission(@RequestBody Permissions permissions) {
|
||||
logger.info("管理员创建权限:{}", permissions);
|
||||
return permissionsService.createPermission(permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新权限信息
|
||||
* @param permissions 权限信息
|
||||
* @return 是否成功
|
||||
*/
|
||||
@PutMapping
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> updatePermission(@RequestBody Permissions permissions) {
|
||||
logger.info("管理员更新权限:{}", permissions);
|
||||
return permissionsService.updatePermission(permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除权限
|
||||
* @param id 权限ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> deletePermission(@PathVariable Long id) {
|
||||
logger.info("管理员删除权限,ID:{}", id);
|
||||
return permissionsService.deletePermission(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除权限
|
||||
* @param ids 权限ID列表
|
||||
* @return 是否成功
|
||||
*/
|
||||
@DeleteMapping("/batch")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> batchDeletePermissions(@RequestBody List<Long> ids) {
|
||||
logger.info("管理员批量删除权限,IDs:{}", ids);
|
||||
return permissionsService.batchDeletePermissions(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据菜单ID查询权限
|
||||
* @param menuId 菜单ID
|
||||
* @return 权限列表
|
||||
*/
|
||||
@GetMapping("/menu/{menuId}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<List<Permissions>> listPermissionsByMenuId(@PathVariable Long menuId) {
|
||||
logger.info("管理员根据菜单ID查询权限,菜单ID:{}", menuId);
|
||||
return permissionsService.listPermissionsByMenuId(menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据权限类型查询权限
|
||||
* @param permissionType 权限类型
|
||||
* @return 权限列表
|
||||
*/
|
||||
@GetMapping("/type/{permissionType}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<List<Permissions>> listPermissionsByType(@PathVariable String permissionType) {
|
||||
logger.info("管理员根据权限类型查询权限,权限类型:{}", permissionType);
|
||||
return permissionsService.listPermissionsByType(permissionType);
|
||||
}
|
||||
}
|
||||
133
src/main/java/com/qf/backend/controller/RolesController.java
Normal file
133
src/main/java/com/qf/backend/controller/RolesController.java
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
*/
|
||||
|
||||
package com.qf.backend.controller;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
import com.qf.backend.common.Result;
|
||||
import com.qf.backend.entity.Roles;
|
||||
import com.qf.backend.service.RolesService;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 角色管理控制器
|
||||
* 处理角色相关的HTTP请求
|
||||
* 遵循RESTful API设计规范
|
||||
* @author 30803
|
||||
*/
|
||||
@RequestMapping("/api/roles")
|
||||
@RestController
|
||||
public class RolesController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RolesController.class);
|
||||
|
||||
@Autowired
|
||||
private RolesService rolesService;
|
||||
|
||||
/**
|
||||
* 查询所有角色
|
||||
* @return 角色列表
|
||||
*/
|
||||
@GetMapping
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<List<Roles>> listAllRoles() {
|
||||
logger.info("管理员查询所有角色");
|
||||
return rolesService.listAllRoles();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID查询角色
|
||||
* @param id 角色ID
|
||||
* @return 角色信息
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Roles> getRoleById(@PathVariable Long id) {
|
||||
logger.info("管理员根据ID查询角色,ID:{}", id);
|
||||
return rolesService.getRoleById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色名称查询角色
|
||||
* @param roleName 角色名称
|
||||
* @return 角色信息
|
||||
*/
|
||||
@GetMapping("/name/{roleName}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Roles> getRoleByName(@PathVariable String roleName) {
|
||||
logger.info("管理员根据名称查询角色,名称:{}", roleName);
|
||||
return rolesService.getRoleByName(roleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询其拥有的角色列表
|
||||
* @param userId 用户ID
|
||||
* @return 角色列表
|
||||
*/
|
||||
@GetMapping("/user/{userId}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<List<Roles>> listRolesByUserId(@PathVariable Long userId) {
|
||||
logger.info("管理员根据用户ID查询角色列表,用户ID:{}", userId);
|
||||
return rolesService.listRolesByUserId(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建角色
|
||||
* @param roles 角色信息
|
||||
* @return 是否成功
|
||||
*/
|
||||
@PostMapping
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> createRole(@RequestBody Roles roles) {
|
||||
logger.info("管理员创建角色:{}", roles);
|
||||
return rolesService.createRole(roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新角色信息
|
||||
* @param roles 角色信息
|
||||
* @return 是否成功
|
||||
*/
|
||||
@PutMapping
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> updateRole(@RequestBody Roles roles) {
|
||||
logger.info("管理员更新角色:{}", roles);
|
||||
return rolesService.updateRole(roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
* @param id 角色ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> deleteRole(@PathVariable Long id) {
|
||||
logger.info("管理员删除角色,ID:{}", id);
|
||||
return rolesService.deleteRole(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除角色
|
||||
* @param ids 角色ID列表
|
||||
* @return 是否成功
|
||||
*/
|
||||
@DeleteMapping("/batch")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> batchDeleteRoles(@RequestBody List<Long> ids) {
|
||||
logger.info("管理员批量删除角色,IDs:{}", ids);
|
||||
return rolesService.batchDeleteRoles(ids);
|
||||
}
|
||||
}
|
||||
169
src/main/java/com/qf/backend/controller/UserRolesController.java
Normal file
169
src/main/java/com/qf/backend/controller/UserRolesController.java
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
*/
|
||||
|
||||
package com.qf.backend.controller;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
import com.qf.backend.common.Result;
|
||||
import com.qf.backend.entity.UserRoles;
|
||||
import com.qf.backend.service.UserRolesService;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户角色关联控制器
|
||||
* 处理用户与角色关联相关的HTTP请求
|
||||
* 遵循RESTful API设计规范
|
||||
* @author 30803
|
||||
*/
|
||||
@RequestMapping("/api/user-roles")
|
||||
@RestController
|
||||
public class UserRolesController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserRolesController.class);
|
||||
|
||||
@Autowired
|
||||
private UserRolesService userRolesService;
|
||||
|
||||
/**
|
||||
* 根据用户ID查询角色关联
|
||||
* @param userId 用户ID
|
||||
* @return 用户角色关联列表
|
||||
*/
|
||||
@GetMapping("/user/{userId}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<List<UserRoles>> getUserRolesByUserId(@PathVariable Long userId) {
|
||||
logger.info("管理员根据用户ID查询角色关联,用户ID:{}", userId);
|
||||
return userRolesService.getUserRolesByUserId(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID查询用户关联
|
||||
* @param roleId 角色ID
|
||||
* @return 用户角色关联列表
|
||||
*/
|
||||
@GetMapping("/role/{roleId}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<List<UserRoles>> getUserRolesByRoleId(@PathVariable Long roleId) {
|
||||
logger.info("管理员根据角色ID查询用户关联,角色ID:{}", roleId);
|
||||
return userRolesService.getUserRolesByRoleId(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为用户添加角色
|
||||
* @param userId 用户ID
|
||||
* @param roleId 角色ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> addRoleToUser(@RequestBody UserRolesRequest request) {
|
||||
logger.info("管理员为用户添加角色,用户ID:{},角色ID:{}", request.getUserId(), request.getRoleId());
|
||||
return userRolesService.addRoleToUser(request.getUserId(), request.getRoleId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 从用户移除角色
|
||||
* @param userId 用户ID
|
||||
* @param roleId 角色ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
@DeleteMapping("/remove")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> removeRoleFromUser(@RequestBody UserRolesRequest request) {
|
||||
logger.info("管理员从用户移除角色,用户ID:{},角色ID:{}", request.getUserId(), request.getRoleId());
|
||||
return userRolesService.removeRoleFromUser(request.getUserId(), request.getRoleId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量为用户添加角色
|
||||
* @param userId 用户ID
|
||||
* @param roleIds 角色ID列表
|
||||
* @return 是否成功
|
||||
*/
|
||||
@PostMapping("/batch-add")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> batchAddRolesToUser(@RequestBody BatchUserRolesRequest request) {
|
||||
logger.info("管理员批量为用户添加角色,用户ID:{},角色ID列表:{}", request.getUserId(), request.getRoleIds());
|
||||
return userRolesService.batchAddRolesToUser(request.getUserId(), request.getRoleIds());
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空用户的所有角色
|
||||
* @param userId 用户ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
@DeleteMapping("/clear/{userId}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> clearUserRoles(@PathVariable Long userId) {
|
||||
logger.info("管理员清空用户的所有角色,用户ID:{}", userId);
|
||||
return userRolesService.clearUserRoles(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否拥有指定角色
|
||||
* @param userId 用户ID
|
||||
* @param roleId 角色ID
|
||||
* @return 是否拥有
|
||||
*/
|
||||
@GetMapping("/check")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Boolean> checkUserHasRole(Long userId, Long roleId) {
|
||||
logger.info("管理员检查用户是否拥有指定角色,用户ID:{},角色ID:{}", userId, roleId);
|
||||
return userRolesService.checkUserHasRole(userId, roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户角色关联请求体
|
||||
*/
|
||||
public static class UserRolesRequest {
|
||||
private Long userId;
|
||||
private Long roleId;
|
||||
|
||||
// getter和setter
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
public Long getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
public void setRoleId(Long roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量用户角色关联请求体
|
||||
*/
|
||||
public static class BatchUserRolesRequest {
|
||||
private Long userId;
|
||||
private List<Long> roleIds;
|
||||
|
||||
// getter和setter
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
public List<Long> getRoleIds() {
|
||||
return roleIds;
|
||||
}
|
||||
public void setRoleIds(List<Long> roleIds) {
|
||||
this.roleIds = roleIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,36 +4,91 @@
|
||||
*/
|
||||
|
||||
package com.qf.backend.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
import com.qf.backend.common.Result;
|
||||
import com.qf.backend.entity.Users;
|
||||
import com.qf.backend.service.UsersService;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* 用户管理控制器
|
||||
* 处理用户相关的HTTP请求
|
||||
* 遵循RESTful API设计规范
|
||||
* @author 30803
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/users")
|
||||
@RestController
|
||||
public class UsersController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(UsersController.class);
|
||||
@Autowired
|
||||
private UsersService usersService;
|
||||
|
||||
@GetMapping("/list")
|
||||
/**
|
||||
* 分页获取用户列表 仅管理员角色
|
||||
* @param pageNum 页码
|
||||
* @param pageSize 每页数量
|
||||
* @return 用户列表
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<List<Users>> listUsersByPage(int pageNum, int pageSize) {
|
||||
logger.info("管理员获取用户列表,页码:{},每页数量:{}", pageNum, pageSize);
|
||||
return usersService.listUsersByPage(pageNum, pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id查询用户 仅管理员角色
|
||||
* @param id 用户ID
|
||||
* @return 用户信息
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Users> getUserById(@PathVariable Long id) {
|
||||
logger.info("管理员根据id查询用户,id:{}", id);
|
||||
return usersService.getUserById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户名查询用户 用户可以查询自己的信息
|
||||
* @param username 用户名
|
||||
* @return 用户信息
|
||||
*/
|
||||
@GetMapping("/username/{username}")
|
||||
// @PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Users> getUserByUsername(@PathVariable String username) {
|
||||
logger.info("管理员根据用户名查询用户,用户名:{}", username);
|
||||
return usersService.getUserByUsername(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据邮箱查询用户 仅管理员角色
|
||||
* @param email 邮箱
|
||||
* @return 用户信息
|
||||
*/
|
||||
@GetMapping("/email/{email}")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<Users> getUserByEmail(@PathVariable String email) {
|
||||
logger.info("管理员根据邮箱查询用户,邮箱:{}", email);
|
||||
return usersService.getUserByEmail(email);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有用户 仅管理员角色
|
||||
* @return 用户列表
|
||||
*/
|
||||
@GetMapping
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public Result<List<Users>> listAllUsers() {
|
||||
logger.info("管理员查询所有用户");
|
||||
return usersService.listAllUsers();
|
||||
}
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public Result<Boolean> deleteUser(Long id) {
|
||||
System.out.println(id);
|
||||
return usersService.deleteUser(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
*/
|
||||
|
||||
package com.qf.backend.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 登录用户DTO(登录时使用)
|
||||
* @param id 用户ID
|
||||
* (登录时返回的用户信息DTO)
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
* @param roles 角色列表
|
||||
@@ -23,10 +23,10 @@ import lombok.NoArgsConstructor;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginUser {
|
||||
private Long id;
|
||||
private String username;
|
||||
private String password;
|
||||
private List<String> roles;
|
||||
private List<String> permissions;
|
||||
public class LoginResponse {
|
||||
private String username; // 用户名
|
||||
private List<String> roles; // 角色列表 暂时无用
|
||||
private List<String> permissions; // 权限列表 暂时无用
|
||||
private String token; // JWT令牌
|
||||
private String tokenType; // 令牌类型,通常为Bearer
|
||||
}
|
||||
@@ -23,7 +23,6 @@ public class RolePermissions {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id; // 关联ID,主键,自增
|
||||
|
||||
private Long roleId; // 角色ID,外键,关联roles表
|
||||
private Long permissionId; // 权限ID,外键,关联permissions表
|
||||
private Date createdAt; // 创建时间
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.qf.backend.entity;
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
@@ -28,6 +29,7 @@ public class Users {
|
||||
private String email; // 邮箱,唯一
|
||||
private String phone; // 手机号,唯一
|
||||
private String avatar; // 头像URL
|
||||
@TableField(exist = false) // 标记该字段在数据库中不存在
|
||||
private Date lastLoginTime; // 最后登录时间
|
||||
private Integer status; // 状态:0:禁用, 1:启用
|
||||
private Date createdAt; // 创建时间
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
package com.qf.backend.service;
|
||||
|
||||
import com.qf.backend.common.Result;
|
||||
import com.qf.backend.dto.LoginUser;
|
||||
import com.qf.backend.dto.LoginResponse;
|
||||
|
||||
/**
|
||||
* 用户登录服务接口
|
||||
@@ -16,7 +16,7 @@ public interface UserLoginService {
|
||||
* 用户登录
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
* @return 登录结果
|
||||
* @return 登录结果,包含登录状态、token等信息
|
||||
*/
|
||||
Result<LoginUser> login(String username, String password);
|
||||
Result<LoginResponse> login(String username, String password);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.qf.backend.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.qf.backend.common.Result;
|
||||
import com.qf.backend.entity.UserRoles;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户角色关联服务接口
|
||||
*/
|
||||
|
||||
@@ -1,158 +1,87 @@
|
||||
package com.qf.backend.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.qf.backend.common.Result;
|
||||
import com.qf.backend.common.ResultUtils;
|
||||
import com.qf.backend.entity.UserDetails;
|
||||
import com.qf.backend.exception.BusinessException;
|
||||
import com.qf.backend.exception.ErrorCode;
|
||||
import com.qf.backend.mapper.UserDetailsMapper;
|
||||
import com.qf.backend.service.UserDetailsService;
|
||||
import com.qf.backend.entity.Roles;
|
||||
import com.qf.backend.entity.UserRoles;
|
||||
import com.qf.backend.entity.Users;
|
||||
import com.qf.backend.service.RolesService;
|
||||
import com.qf.backend.service.UserRolesService;
|
||||
import com.qf.backend.service.UsersService;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 用户详情服务实现类
|
||||
* UserDetailsService实现类,用于从数据库中加载用户信息
|
||||
* 该类实现了Spring Security的UserDetailsService接口,用于根据用户名加载用户信息
|
||||
*/
|
||||
@Service
|
||||
public class UserDetailsServiceImpl extends ServiceImpl<UserDetailsMapper, UserDetails> implements UserDetailsService {
|
||||
public class UserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
/**
|
||||
* 注入用户服务,用于查询用户信息
|
||||
*/
|
||||
@Autowired
|
||||
private UserDetailsMapper userDetailsMapper;
|
||||
private UsersService usersService;
|
||||
@Autowired
|
||||
private UserRolesService userRolesService;
|
||||
@Autowired
|
||||
private RolesService RolesService;
|
||||
|
||||
/**
|
||||
* 根据用户名加载用户信息
|
||||
* @param username 用户名
|
||||
* @return UserDetails 用户详情对象,包含用户名、密码、权限等信息
|
||||
* @throws UsernameNotFoundException 如果用户名不存在
|
||||
*/
|
||||
@Override
|
||||
public Result<UserDetails> getUserDetailsByUserId(Long userId) {
|
||||
if (userId == null) {
|
||||
throw new BusinessException(ErrorCode.MISSING_PARAM, "用户ID不能为空");
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
// 1. 从数据库中查询用户
|
||||
Result<Users> result = usersService.getUserByUsername(username);
|
||||
if (result == null || result.getData() == null) {
|
||||
throw new UsernameNotFoundException("用户名不存在: " + username);
|
||||
}
|
||||
try {
|
||||
UserDetails userDetails = userDetailsMapper.selectOne(
|
||||
new QueryWrapper<UserDetails>().eq("user_id", userId));
|
||||
return ResultUtils.success(userDetails);
|
||||
} catch (BusinessException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(ErrorCode.DATABASE_ERROR, "查询用户详情失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Boolean> createUserDetails(UserDetails userDetails) {
|
||||
if (userDetails == null) {
|
||||
throw new BusinessException(ErrorCode.MISSING_PARAM, "用户详情信息不能为空");
|
||||
Users user = result.getData();
|
||||
|
||||
// 2. 构建权限列表(这里简化处理,实际应从数据库中查询用户的角色和权限)
|
||||
List<GrantedAuthority> authorities = new ArrayList<>();
|
||||
// 查询用户角色关联
|
||||
Result<List<UserRoles>> userRoleResultList = userRolesService.getUserRolesByUserId(user.getId());
|
||||
if (userRoleResultList == null || userRoleResultList.getData() == null) {
|
||||
throw new UsernameNotFoundException("用户角色不存在: " + user.getId());
|
||||
}
|
||||
if (userDetails.getUserId() == null) {
|
||||
throw new BusinessException(ErrorCode.MISSING_PARAM, "用户ID不能为空");
|
||||
}
|
||||
try {
|
||||
// 检查是否已存在该用户的详情
|
||||
UserDetails existing = userDetailsMapper.selectOne(
|
||||
new QueryWrapper<UserDetails>().eq("user_id", userDetails.getUserId()));
|
||||
if (existing != null) {
|
||||
throw new BusinessException(ErrorCode.BUSINESS_ERROR, "该用户已存在详情信息");
|
||||
// 3. 查询角色权限
|
||||
for (UserRoles userRole : userRoleResultList.getData()) {
|
||||
Result<Roles> roleResult = RolesService.getRoleById(userRole.getRoleId());
|
||||
if (roleResult == null || roleResult.getData() == null) {
|
||||
throw new UsernameNotFoundException("权限不存在: " + userRole.getRoleId());
|
||||
}
|
||||
int result = userDetailsMapper.insert(userDetails);
|
||||
return ResultUtils.success(result > 0);
|
||||
} catch (BusinessException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(ErrorCode.DATABASE_ERROR, "创建用户详情失败", e);
|
||||
Roles role = roleResult.getData();
|
||||
// 4. 转换为Spring Security的GrantedAuthority对象
|
||||
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName().toUpperCase()));
|
||||
}
|
||||
// 3. 返回UserDetails对象
|
||||
// 注意:在实际应用中,密码应该加密存储,这里直接使用明文密码(仅用于演示)
|
||||
return User.builder()
|
||||
.username(user.getUsername()) // 用户名
|
||||
.password(user.getPassword()) // 密码需要加密存储,这里直接使用明文密码(仅用于演示)
|
||||
.authorities(authorities) // 假设用户默认拥有USER权限
|
||||
.accountExpired(false) // 假设账号永不过期
|
||||
.accountLocked(false) // 假设账号永不过期
|
||||
.credentialsExpired(false) // 假设密码永不过期
|
||||
.disabled(user.getStatus() == 0) // 假设status为0表示禁用
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Boolean> updateUserDetails(UserDetails userDetails) {
|
||||
if (userDetails == null) {
|
||||
throw new BusinessException(ErrorCode.MISSING_PARAM, "用户详情信息不能为空");
|
||||
}
|
||||
if (userDetails.getId() == null) {
|
||||
throw new BusinessException(ErrorCode.MISSING_PARAM, "用户详情ID不能为空");
|
||||
}
|
||||
try {
|
||||
// 检查用户详情是否存在
|
||||
UserDetails existing = userDetailsMapper.selectById(userDetails.getId());
|
||||
if (existing == null) {
|
||||
throw new BusinessException(ErrorCode.NOT_FOUND, "用户详情不存在");
|
||||
}
|
||||
int result = userDetailsMapper.updateById(userDetails);
|
||||
return ResultUtils.success(result > 0);
|
||||
} catch (BusinessException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(ErrorCode.DATABASE_ERROR, "更新用户详情失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Boolean> deleteUserDetailsByUserId(Long userId) {
|
||||
if (userId == null) {
|
||||
throw new BusinessException(ErrorCode.MISSING_PARAM, "用户ID不能为空");
|
||||
}
|
||||
try {
|
||||
// 检查用户详情是否存在
|
||||
UserDetails existing = userDetailsMapper.selectOne(
|
||||
new QueryWrapper<UserDetails>().eq("user_id", userId));
|
||||
if (existing == null) {
|
||||
throw new BusinessException(ErrorCode.NOT_FOUND, "用户详情不存在");
|
||||
}
|
||||
int result = userDetailsMapper.delete(
|
||||
new QueryWrapper<UserDetails>().eq("user_id", userId));
|
||||
return ResultUtils.success(result > 0);
|
||||
} catch (BusinessException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(ErrorCode.DATABASE_ERROR, "删除用户详情失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<UserDetails> getUserDetailsById(Long id) {
|
||||
if (id == null) {
|
||||
throw new BusinessException(ErrorCode.MISSING_PARAM, "用户详情ID不能为空");
|
||||
}
|
||||
try {
|
||||
UserDetails userDetails = userDetailsMapper.selectById(id);
|
||||
if (userDetails == null) {
|
||||
throw new BusinessException(ErrorCode.NOT_FOUND, "用户详情不存在");
|
||||
}
|
||||
return ResultUtils.success(userDetails);
|
||||
} catch (BusinessException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(ErrorCode.DATABASE_ERROR, "查询用户详情失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public Result<Boolean> updateContactInfo(Long userId, String phone, String email) {
|
||||
// if (userId == null) {
|
||||
// throw new BusinessException(ErrorCode.MISSING_PARAM, "用户ID不能为空");
|
||||
// }
|
||||
// if (ValidateUtil.isEmpty(phone) && ValidateUtil.isEmpty(email)) {
|
||||
// throw new BusinessException(ErrorCode.MISSING_PARAM, "手机号和邮箱不能同时为空");
|
||||
// }
|
||||
// try {
|
||||
// // 检查用户详情是否存在
|
||||
// UserDetails existing = userDetailsMapper.selectOne(
|
||||
// new QueryWrapper<UserDetails>().eq("user_id", userId));
|
||||
// if (existing == null) {
|
||||
// throw new BusinessException(ErrorCode.NOT_FOUND, "用户详情不存在");
|
||||
// }
|
||||
// // 更新联系方式
|
||||
// if (phone != null) {
|
||||
// existing.setPhone(phone);
|
||||
// }
|
||||
// if (email != null) {
|
||||
// existing.setEmail(email);
|
||||
// }
|
||||
// int result = userDetailsMapper.updateById(existing);
|
||||
// return ResultUtils.success(result > 0);
|
||||
// } catch (BusinessException e) {
|
||||
// throw e;
|
||||
// } catch (Exception e) {
|
||||
// throw new BusinessException(ErrorCode.DATABASE_ERROR, "更新用户联系方式失败", e);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import com.qf.backend.common.Result;
|
||||
import com.qf.backend.common.ResultUtils;
|
||||
import com.qf.backend.dto.LoginUser;
|
||||
import com.qf.backend.dto.LoginResponse;
|
||||
import com.qf.backend.entity.Permissions;
|
||||
import com.qf.backend.entity.Roles;
|
||||
import com.qf.backend.entity.UserRoles;
|
||||
@@ -57,17 +57,15 @@ public class UserLoginServiceImpl implements UserLoginService {
|
||||
* @return 登录结果
|
||||
*/
|
||||
@Override
|
||||
public Result<LoginUser> login(String username, String password) {
|
||||
public Result<LoginResponse> login(String username, String password) {
|
||||
logger.info("用户登录,用户名:{}", username);
|
||||
// 1. 校验用户名和密码是否为空
|
||||
try{
|
||||
if (ValidateUtil.isEmpty(username) || ValidateUtil.isEmpty(password)) {
|
||||
throw new IllegalArgumentException("用户名或密码不能为空");
|
||||
}
|
||||
// 加密密码
|
||||
String encryptedPassword = ValidateUtil.encryptPassword(password);
|
||||
// 2. 登录
|
||||
Result<Users> result = usersServiceImpl.login(username, encryptedPassword);
|
||||
Result<Users> result = usersServiceImpl.login(username, password);
|
||||
if (result == null || result.getData() == null) {
|
||||
throw new IllegalArgumentException("用户名不存在或密码错误");
|
||||
}
|
||||
@@ -87,7 +85,7 @@ public class UserLoginServiceImpl implements UserLoginService {
|
||||
for (UserRoles ur : userRoles) {
|
||||
Roles role = rolesServiceImpl.getById(ur.getRoleId());
|
||||
if (role != null) {
|
||||
roleNames.add(role.getRoleName());
|
||||
roleNames.add(String.valueOf(role.getRoleType()));
|
||||
roleIds.add(role.getId());
|
||||
}
|
||||
}
|
||||
@@ -104,14 +102,12 @@ public class UserLoginServiceImpl implements UserLoginService {
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 构建LoginUser对象
|
||||
LoginUser loginUser = new LoginUser();
|
||||
loginUser.setId(user.getId());
|
||||
loginUser.setUsername(user.getUsername());
|
||||
loginUser.setRoles(new ArrayList<>(roleNames));
|
||||
loginUser.setPermissions(new ArrayList<>(permissionCodes));
|
||||
|
||||
return ResultUtils.success(loginUser);
|
||||
// 6. 构建LoginResponse对象
|
||||
LoginResponse loginResponse = new LoginResponse();
|
||||
loginResponse.setUsername(user.getUsername());
|
||||
loginResponse.setRoles(new ArrayList<>(roleNames));
|
||||
loginResponse.setPermissions(new ArrayList<>(permissionCodes));
|
||||
return ResultUtils.success(loginResponse);
|
||||
} catch (Exception e) {
|
||||
logger.error("用户登录失败,用户名:{}", username, e);
|
||||
return ResultUtils.fail(ErrorCode.SYSTEM_ERROR, e.getMessage());
|
||||
|
||||
@@ -88,12 +88,18 @@ public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements
|
||||
throw new BusinessException(ErrorCode.INVALID_PARAM, "用户名或密码不能为空");
|
||||
}
|
||||
|
||||
// 校验用户名是否存在
|
||||
Users user = usersMapper.login(username, password);
|
||||
// 根据用户名查询用户
|
||||
Users user = usersMapper.selectByUsername(username);
|
||||
if (user == null) {
|
||||
throw new BusinessException(ErrorCode.USER_NOT_FOUND, "用户名不存在或密码错误");
|
||||
}
|
||||
|
||||
// 使用BCryptPasswordEncoder验证密码
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
if (!passwordEncoder.matches(password, user.getPassword())) {
|
||||
throw new BusinessException(ErrorCode.USER_NOT_FOUND, "用户名不存在或密码错误");
|
||||
}
|
||||
|
||||
return ResultUtils.success(user);
|
||||
} catch (BusinessException e) {
|
||||
throw e;
|
||||
|
||||
@@ -6,4 +6,4 @@ spring.datasource.username=root
|
||||
spring.datasource.password=123456
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
# 暂时关闭Spring Security
|
||||
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
||||
# spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
||||
|
||||
Reference in New Issue
Block a user