大致权限控制完成,新增优化权限控制代码

master
赵亚鹏 6 days ago
parent d61a2422b6
commit 99128aa40c

@ -0,0 +1,51 @@
package cn.zyp.stusystem.common;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.naming.AuthenticationException;
import java.nio.file.AccessDeniedException;
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理SaToken未登录异常
@ExceptionHandler(NotLoginException.class)
public Result<Void> handleNotLoginException(NotLoginException e) {
return Result.error(401, "未登录或登录已过期");
}
// 处理SaToken权限不足异常
@ExceptionHandler(NotPermissionException.class)
public Result<Void> handleNotPermissionException(NotPermissionException e) {
return Result.error(403, "无权限访问");
}
// 处理SaToken角色不足异常
@ExceptionHandler(NotRoleException.class)
public Result<Void> handleNotRoleException(NotRoleException e) {
return Result.error(403, "无角色权限");
}
// 处理其他认证异常
@ExceptionHandler(AuthenticationException.class)
public Result<Void> handleException(AuthenticationException e){
return Result.error(401, e.getMessage());
}
// 处理其他权限不足异常
@ExceptionHandler(AccessDeniedException.class)
public Result<Void> handleAccessDeniedException(AccessDeniedException e) {
return Result.error(403, e.getMessage());
}
// 处理其他未知异常
@ExceptionHandler(Exception.class)
public Result<Void> handleException(Exception e) {
e.printStackTrace();
return Result.error(500, "服务器内部错误");
}
}

@ -0,0 +1,63 @@
package cn.zyp.stusystem.common;
import lombok.Data;
@Data
public class Result<T> {
//响应码
private int code;
//响应消息
private String msg;
//响应数据
private T data;
private Result(){}
/**
*
* @param data
* @param <T>
* @return Result
*/
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMsg("success");
result.setData(data);
return result;
}
/**
*
* @param <T>
* @return Result
*/
public static <T> Result<T> success() {
return success(null);
}
/**
*
* @param code
* @param msg
* @param <T>
* @return Result
*/
public static <T> Result<T> error(int code, String msg) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMsg(msg);
result.setData(null);
return result;
}
/**
* 500
* @param msg
* @param <T>
* @return Result
*/
public static <T> Result<T> error(String msg) {
return error(500, msg);
}
}

@ -0,0 +1,23 @@
package cn.zyp.stusystem.common;
public enum ResultCode {
SUCCESS(200,"成功"),
ERROR(500,"错误"),
PARAM_ERROR(400,"参数错误");
private final int code;
private final String message;
ResultCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}

@ -0,0 +1,24 @@
package cn.zyp.stusystem.config;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.util.SaResult;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SaTokenConfig {
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
.addInclude("/**")
.addExclude("/favicon.ico")
.setAuth(obj -> {
// 这里不需要写权限校验,让注解来处理
// SaRouter.match("/**").notMatch("/api/login").check(StpUtil::checkLogin);
})
.setError(e -> {
return SaResult.error(e.getMessage());
});
}
}

@ -0,0 +1,24 @@
package cn.zyp.stusystem.config;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class StpInterfaceImpl implements StpInterface {
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// 从Session获取权限
return (List<String>) StpUtil.getSessionByLoginId(loginId).get("permissions");
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
String role = (String) StpUtil.getSessionByLoginId(loginId).get("role");
return Arrays.asList(role);
}
}

@ -0,0 +1,42 @@
package cn.zyp.stusystem.constant;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// constant/PermissionConstants.java
public class PermissionConstants {
public static final String ROLE_ADMIN = "admin";
public static final String ROLE_HEAD_TEACHER = "head_teacher";
public static final String ROLE_TEACHER = "teacher";
public static final String CLASS_VIEW = "class:view";
public static final String CLASS_ADD = "class:add";
public static final String CLASS_EDIT = "class:edit";
public static final String CLASS_DELETE = "class:delete";
public static final String STUDENT_VIEW = "student:view";
public static final String STUDENT_ADD = "student:add";
public static final String STUDENT_EDIT = "student:edit";
public static final String STUDENT_DELETE = "student:delete";
public static final Map<String, List<String>> ROLE_PERMISSIONS = new HashMap<>();
static {
ROLE_PERMISSIONS.put(ROLE_ADMIN, Arrays.asList(
CLASS_VIEW, CLASS_ADD, CLASS_EDIT, CLASS_DELETE,
STUDENT_VIEW, STUDENT_ADD, STUDENT_EDIT, STUDENT_DELETE
));
ROLE_PERMISSIONS.put(ROLE_HEAD_TEACHER, Arrays.asList(
CLASS_VIEW,
STUDENT_VIEW, STUDENT_ADD, STUDENT_EDIT, STUDENT_DELETE
));
ROLE_PERMISSIONS.put(ROLE_TEACHER, Arrays.asList(
CLASS_VIEW,
STUDENT_VIEW
));
}
}

@ -0,0 +1,58 @@
package cn.zyp.stusystem.controller;
import cn.dev33.satoken.stp.StpUtil;
import cn.zyp.stusystem.common.Result;
import cn.zyp.stusystem.constant.PermissionConstants;
import cn.zyp.stusystem.dto.LoginDTO;
import cn.zyp.stusystem.entity.User;
import cn.zyp.stusystem.service.UserService;
import cn.zyp.stusystem.vo.LoginResult;
import cn.zyp.stusystem.vo.UserVO;
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 java.util.List;
@RestController
@RequestMapping("/api")
public class LoginController {
@Autowired
private UserService userService;
@PostMapping("/login")
public Result<LoginResult> login(@RequestBody LoginDTO loginDTO) {
// 1. 根据用户名查询用户信息
User user = userService.getByUsername(loginDTO.getUsername());
// 2. 校验用户是否存在以及密码是否正确
if(user == null || !user.getPassword().equals(loginDTO.getPassword())) {
return Result.error(401, "用户名或密码错误");
}
// 3. SaToken登录自动生成token
StpUtil.login(user.getId());
// 4. 在Session中存储角色和权限
StpUtil.getSession().set("role", user.getRole());
List<String> permissions = PermissionConstants.ROLE_PERMISSIONS.get(user.getRole());
StpUtil.getSession().set("permissions", permissions);
// 5. 构建返回数据
UserVO userVO = new UserVO();
userVO.setId(user.getId());
userVO.setUsername(user.getUsername());
userVO.setRole(user.getRole());
userVO.setName(user.getName());
userVO.setPermissions(permissions);
LoginResult loginResult = new LoginResult();
loginResult.setToken(StpUtil.getTokenValue());
loginResult.setUserInfo(userVO);
return Result.success(loginResult);
}
}

@ -0,0 +1,38 @@
package cn.zyp.stusystem.controller;
import cn.zyp.stusystem.common.Result;
import cn.zyp.stusystem.entity.Permission;
import cn.zyp.stusystem.service.PermissionService;
import cn.zyp.stusystem.vo.PermissionVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/permission")
public class PermissionController {
@Autowired
private PermissionService permissionService;
/**
*
*/
@GetMapping("/all")
public Result<List<PermissionVO>> getAllPermissions() {
List<Permission> permissions = permissionService.getAllEnabledPermissions();
List<PermissionVO> voList = permissions.stream()
.map(permission -> {
PermissionVO vo = new PermissionVO();
BeanUtils.copyProperties(permission, vo);
return vo;
})
.collect(Collectors.toList());
return Result.success(voList);
}
}

@ -0,0 +1,37 @@
package cn.zyp.stusystem.controller;
import cn.zyp.stusystem.common.Result;
import cn.zyp.stusystem.dto.SaveRolePermissionsDTO;
import cn.zyp.stusystem.service.RolePermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/role")
public class RolePermissionController {
@Autowired
private RolePermissionService rolePermissionService;
/**
*
*/
@GetMapping("/{roleId}/permissions")
public Result<List<String>> getRolePermissions(@PathVariable Long roleId) {
List<String> permissionCodes = rolePermissionService.getPermissionCodesByRoleId(roleId);
return Result.success(permissionCodes);
}
/**
*
*/
@PostMapping("/{roleId}/permissions")
public Result<Boolean> saveRolePermissions(
@PathVariable Long roleId,
@RequestBody SaveRolePermissionsDTO dto) {
rolePermissionService.saveRolePermissions(roleId, dto.getPermissions());
return Result.success(true);
}
}

@ -0,0 +1,9 @@
package cn.zyp.stusystem.dto;
import lombok.Data;
@Data
public class LoginDTO {
private String username;
private String password;
}

@ -0,0 +1,9 @@
package cn.zyp.stusystem.dto;
import lombok.Data;
import java.util.List;
@Data
public class SaveRolePermissionsDTO {
private List<String> permissions; // 权限码列表
}

@ -0,0 +1,25 @@
package cn.zyp.stusystem.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("permissions")
public class Permission {
@TableId(type = IdType.AUTO)
private Long id;
private String code; // 权限码,如 student:add
private String name; // 权限名称,如 学生新增
private String module; // 所属模块,如 student
private String moduleName; // 模块名称,如 学生管理
private String description; // 权限描述
private Integer sortOrder; // 排序顺序
private Integer status; // 状态1-启用0-禁用
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}

@ -0,0 +1,21 @@
package cn.zyp.stusystem.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("roles")
public class Role {
@TableId(type = IdType.AUTO)
private Long id;
private String roleCode; // 角色代码,如 admin
private String roleName; // 角色名称,如 管理员
private Integer status; // 状态1-启用0-禁用
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}

@ -0,0 +1,19 @@
package cn.zyp.stusystem.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("role_permissions")
public class RolePermission {
@TableId(type = IdType.AUTO)
private Long id;
private Long roleId; // 角色ID
private String permissionCode; // 权限码
private LocalDateTime createdAt;
}

@ -0,0 +1,23 @@
package cn.zyp.stusystem.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password;
private String role; // admin, head_teacher, teacher保留用于兼容
private Long roleId; // 角色ID新增字段
private String name;
private Integer status;
private Date createTime;
}

@ -0,0 +1,9 @@
package cn.zyp.stusystem.mapper;
import cn.zyp.stusystem.entity.Permission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PermissionMapper extends BaseMapper<Permission> {
}

@ -0,0 +1,10 @@
package cn.zyp.stusystem.mapper;
import cn.zyp.stusystem.entity.Role;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RoleMapper extends BaseMapper<Role> {
// 不需要自定义方法直接在Service中使用LambdaQueryWrapper
}

@ -0,0 +1,10 @@
package cn.zyp.stusystem.mapper;
import cn.zyp.stusystem.entity.RolePermission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RolePermissionMapper extends BaseMapper<RolePermission> {
// 不需要自定义方法直接在Service中使用LambdaQueryWrapper
}

@ -0,0 +1,9 @@
package cn.zyp.stusystem.mapper;
import cn.zyp.stusystem.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

@ -0,0 +1,13 @@
package cn.zyp.stusystem.service;
import cn.zyp.stusystem.entity.Permission;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface PermissionService extends IService<Permission> {
/**
*
*/
List<Permission> getAllEnabledPermissions();
}

@ -0,0 +1,23 @@
package cn.zyp.stusystem.service;
import com.baomidou.mybatisplus.extension.service.IService;
import cn.zyp.stusystem.entity.RolePermission;
import java.util.List;
public interface RolePermissionService extends IService<RolePermission> {
/**
* ID
*/
List<String> getPermissionCodesByRoleId(Long roleId);
/**
* ID
*/
List<String> getPermissionCodesByRoleIds(List<Long> roleIds);
/**
*
*/
void saveRolePermissions(Long roleId, List<String> permissionCodes);
}

@ -0,0 +1,11 @@
package cn.zyp.stusystem.service;
import cn.zyp.stusystem.entity.Role;
import com.baomidou.mybatisplus.extension.service.IService;
public interface RoleService extends IService<Role> {
/**
* ID
*/
Long getRoleIdByRoleCode(String roleCode);
}

@ -0,0 +1,18 @@
package cn.zyp.stusystem.service;
import cn.zyp.stusystem.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface UserService extends IService<User> {
/**
*
*/
User getByUsername(String username);
/**
* ID
*/
List<String> getUserPermissions(Long userId);
}

@ -0,0 +1,23 @@
package cn.zyp.stusystem.service.impl;
import cn.zyp.stusystem.entity.Permission;
import cn.zyp.stusystem.mapper.PermissionMapper;
import cn.zyp.stusystem.service.PermissionService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission>
implements PermissionService {
@Override
public List<Permission> getAllEnabledPermissions() {
return list(new LambdaQueryWrapper<Permission>()
.eq(Permission::getStatus, 1)
.orderByAsc(Permission::getModule, Permission::getSortOrder)
);
}
}

@ -0,0 +1,75 @@
package cn.zyp.stusystem.service.impl;
import cn.zyp.stusystem.entity.RolePermission;
import cn.zyp.stusystem.mapper.RolePermissionMapper;
import cn.zyp.stusystem.service.RolePermissionService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class RolePermissionServiceImpl extends ServiceImpl<RolePermissionMapper, RolePermission>
implements RolePermissionService {
@Override
public List<String> getPermissionCodesByRoleId(Long roleId) {
if (roleId == null) {
return List.of();
}
// 使用MyBatis-Plus的LambdaQueryWrapper查询
List<RolePermission> list = list(new LambdaQueryWrapper<RolePermission>()
.eq(RolePermission::getRoleId, roleId)
.select(RolePermission::getPermissionCode) // 只查询permission_code字段
);
// 提取permissionCode
return list.stream()
.map(RolePermission::getPermissionCode)
.collect(Collectors.toList());
}
@Override
public List<String> getPermissionCodesByRoleIds(List<Long> roleIds) {
if (roleIds == null || roleIds.isEmpty()) {
return List.of();
}
// 使用MyBatis-Plus的in查询
List<RolePermission> list = list(new LambdaQueryWrapper<RolePermission>()
.in(RolePermission::getRoleId, roleIds)
.select(RolePermission::getPermissionCode) // 只查询permission_code字段
);
// 提取permissionCode并去重
return list.stream()
.map(RolePermission::getPermissionCode)
.distinct() // 去重
.collect(Collectors.toList());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void saveRolePermissions(Long roleId, List<String> permissionCodes) {
// 1. 删除该角色的所有现有权限使用MyBatis-Plus的remove方法
remove(new LambdaQueryWrapper<RolePermission>()
.eq(RolePermission::getRoleId, roleId)
);
// 2. 批量插入新权限
if (permissionCodes != null && !permissionCodes.isEmpty()) {
List<RolePermission> rolePermissions = permissionCodes.stream()
.map(code -> {
RolePermission rp = new RolePermission();
rp.setRoleId(roleId);
rp.setPermissionCode(code);
rp.setCreatedAt(LocalDateTime.now());
return rp;
})
.collect(Collectors.toList());
saveBatch(rolePermissions);
}
}
}

@ -0,0 +1,21 @@
package cn.zyp.stusystem.service.impl;
import cn.zyp.stusystem.entity.Role;
import cn.zyp.stusystem.mapper.RoleMapper;
import cn.zyp.stusystem.service.RoleService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {
@Override
public Long getRoleIdByRoleCode(String roleCode) {
Role role = getOne(new LambdaQueryWrapper<Role>()
.eq(Role::getRoleCode, roleCode)
.eq(Role::getStatus, 1)
);
return role != null ? role.getId() : null;
}
}

@ -0,0 +1,15 @@
package cn.zyp.stusystem.service.impl;
import cn.zyp.stusystem.entity.User;
import cn.zyp.stusystem.mapper.UserMapper;
import cn.zyp.stusystem.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public User getByUsername(String username) {
return lambdaQuery().eq(User::getUsername,username).one();
}
}

@ -0,0 +1,10 @@
package cn.zyp.stusystem.vo;
import cn.zyp.stusystem.vo.UserVO;
import lombok.Data;
@Data
public class LoginResult {
private String token;
private UserVO userInfo;
}

@ -0,0 +1,11 @@
package cn.zyp.stusystem.vo;
import lombok.Data;
@Data
public class PermissionVO {
private String code; // 权限码
private String name; // 权限名称
private String module; // 所属模块
private String moduleName; // 模块名称
}

@ -0,0 +1,14 @@
package cn.zyp.stusystem.vo;
import lombok.Data;
import java.util.List;
@Data
public class UserVO {
private Long id;
private String username;
private String role;
private String name;
private List<String> permissions;
}
Loading…
Cancel
Save