sxwz2.0/src/main/java/art/kexue/sxwz/aspect/EduPermissionAspect.java
wangzhiwei 5f5c0759ce feat(notification): 实现通知功能,支持角色层级发送和课程群发
1. 修改 SysNotification 实体,新增 senderId, senderName, targetType 字段

2. 新增 SendNotificationRequest 请求DTO

3. 扩展通知类型至6种(新增用户通知、课程通知)

4. 实现角色层级权限控制,支持多级管理员通知下级

5. 支持老师群发课程通知给学生

6. 新增批量发送接口和权限配置
2026-05-15 16:57:07 +08:00

170 lines
6.8 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package art.kexue.sxwz.aspect;
import art.kexue.sxwz.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
@Aspect
@Component
@Slf4j
public class EduPermissionAspect {
@Resource
private RedissonClient redissonClient;
@Around("execution(* art.kexue.sxwz.service.impl.Edu*ServiceImpl.*(..))")
public Object checkEduPermission(ProceedingJoinPoint joinPoint) throws Throwable {
try {
cn.dev33.satoken.stp.StpUtil.checkLogin();
Long userId = cn.dev33.satoken.stp.StpUtil.getLoginIdAsLong();
String token = cn.dev33.satoken.stp.StpUtil.getTokenValue();
// SUPER角色拥有所有权限直接放行
if (cn.dev33.satoken.stp.StpUtil.hasRole("SUPER")) {
log.info("用户ID: {} 拥有SUPER角色直接放行访问方法: {}", userId, joinPoint.getSignature().getName());
return joinPoint.proceed();
}
List<String> permissions = getUserPermissions(token);
String requiredPermission = generatePermissionCode(joinPoint);
log.info("用户ID: {}, 访问方法: {}, 需要权限: {}",
userId,
joinPoint.getSignature().getName(),
requiredPermission);
if (permissions == null || permissions.isEmpty()) {
log.warn("用户未配置任何权限");
throw new BizException(403, "没有相应操作权限");
}
if (!permissions.contains(requiredPermission)) {
log.warn("用户缺少权限: {}", requiredPermission);
throw new BizException(403, "没有相应操作权限");
}
log.info("权限验证通过: {}", requiredPermission);
} catch (cn.dev33.satoken.exception.NotLoginException e) {
log.error("未登录:{}", e.getMessage());
throw new BizException(401, "请先登录认证后操作");
} catch (BizException e) {
throw e;
} catch (Exception e) {
log.error("权限验证失败:{}", e.getMessage());
throw new BizException(403, "权限验证失败");
}
return joinPoint.proceed();
}
private List<String> getUserPermissions(String token) {
try {
String loginUserJson = (String) redissonClient.getBucket("loginUser:" + token).get();
if (loginUserJson != null && !loginUserJson.isEmpty()) {
cn.hutool.json.JSONObject jsonObject = cn.hutool.json.JSONUtil.parseObj(loginUserJson);
cn.hutool.json.JSONArray permissionsArray = jsonObject.getJSONArray("permissions");
if (permissionsArray != null) {
return permissionsArray.toList(String.class);
}
}
} catch (Exception e) {
log.error("从Redis获取用户权限失败{}", e.getMessage());
}
return Collections.emptyList();
}
private String generatePermissionCode(ProceedingJoinPoint joinPoint) {
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
String module = extractModule(className);
String action = extractAction(methodName);
return String.format("%s:%s", module, action);
}
private String extractModule(String className) {
if (className.startsWith("EduCourse")) {
return "course";
} else if (className.startsWith("EduStudent")) {
return "user:student";
} else if (className.startsWith("EduTeacher")) {
return "user:teacher";
} else if (className.startsWith("EduHomework")) {
return "homework";
} else if (className.startsWith("EduExam")) {
return "exam";
} else if (className.startsWith("EduAttendance")) {
return "attendance";
} else if (className.startsWith("EduExcellentWork")) {
return "excellent";
}else if (className.startsWith("EduSchool")) {
return "school";
} else {
return className.replace("Edu", "").replace("ServiceImpl", "").toLowerCase();
}
}
private String extractAction(String methodName) {
if (methodName.startsWith("save") || methodName.startsWith("create")) {
return "add";
} else if (methodName.startsWith("update") && !methodName.startsWith("updateStatus")) {
return "update"; // 修改update方法返回update而非edit
} else if (methodName.startsWith("updateStatus")) {
return "updateStatus"; // 新增:状态变更方法
} else if (methodName.startsWith("edit")) {
return "edit";
} else if (methodName.startsWith("delete") || methodName.startsWith("remove")) {
return "delete";
} else if (methodName.equals("pageList")) {
return "pageList"; // 新增:分页查询方法
} else if (methodName.startsWith("query") || methodName.startsWith("get") || methodName.startsWith("list")) {
return "query";
} else if (methodName.startsWith("addStudent")) {
return "student:add";
} else if (methodName.startsWith("removeStudent")) {
return "student:remove";
} else if (methodName.startsWith("submit")) {
return "submit";
} else if (methodName.startsWith("grade")) {
return "grade";
} else if (methodName.startsWith("publish")) {
return "publish";
} else if (methodName.startsWith("mark")) {
return "mark";
} else if (methodName.startsWith("addLike")) {
return "like";
} else if (methodName.startsWith("removeLike")) {
return "like:remove";
} else if (methodName.startsWith("countLikes")) {
return "like:count";
} else if (methodName.startsWith("recordAttendance")) {
return "record";
} else if (methodName.startsWith("batchCreate")) {
return "batch:add";
} else if (methodName.startsWith("isStudentIn")) {
return "student:exists";
} else if (methodName.startsWith("sendNotification")) {
return "notification:send";
} else if (methodName.startsWith("markAsRead")) {
return "notification:read";
} else if (methodName.startsWith("createMakeup")) {
return "makeup";
} else {
return methodName.toLowerCase();
}
}
}