You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring MVC+Spring Security如何实现动态端点的动态权限访问控制

实现方案

方案1:自定义Spring Security表达式+注解鉴权(推荐)

这种方式利用Spring Security原生的扩展能力,代码侵入性低,适配注解式鉴权习惯。

  • 第一步:自定义权限校验工具类
    实现一个Spring管理的Bean,封装课程角色查询逻辑,示例代码:
    @Component("coursePermissionChecker")
    public class CoursePermissionChecker {
        @Autowired
        private UserCourseRoleDao userCourseRoleDao;
    
        public boolean hasCourseRole(Long courseId, String... roles) {
            // 获取当前登录用户ID
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            if (auth == null) return false;
            Long userId = ((LoginUser) auth.getPrincipal()).getUserId();
            // 兼容全局管理员:有管理员角色直接放行
            if (auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"))) {
                return true;
            }
            // 查询用户在对应课程的角色匹配
            List<String> userRoles = userCourseRoleDao.listUserCourseRoles(userId, courseId);
            return Arrays.stream(roles).anyMatch(userRoles::contains);
        }
    }
    
  • 第二步:在Controller层直接使用注解鉴权
    借助SpEL表达式直接获取路径参数,调用自定义校验逻辑,同时根据角色返回不同视图:
    @GetMapping("/course/{courseId}")
    @PreAuthorize("@coursePermissionChecker.hasCourseRole(#courseId, 'TEACHER', 'STUDENT')")
    public String getCourseDetailPage(@PathVariable Long courseId, Model model) {
        // 额外判断角色返回对应视图
        if (coursePermissionChecker.hasCourseRole(courseId, "TEACHER")) {
            // 教师视图可以额外加载公告编辑、成绩管理等模块数据
            model.addAttribute("isTeacher", true);
            return "course/teacher_detail";
        }
        model.addAttribute("isTeacher", false);
        return "course/student_detail";
    }
    
    注意需要先开启Spring Security的方法级注解:在配置类上加@EnableGlobalMethodSecurity(prePostEnabled = true)

方案2:拦截器统一处理(适合批量接口校验)

如果大量接口都携带courseId路径参数,不想逐个加注解,可以用Spring MVC拦截器统一处理:

  • 实现HandlerInterceptor接口,在preHandle阶段从URI提取courseId,完成权限校验,把查询到的课程角色存入请求上下文:
    @Component
    public class CoursePermissionInterceptor implements HandlerInterceptor {
        @Autowired
        private CoursePermissionChecker permissionChecker;
        private AntPathMatcher antPathMatcher = new AntPathMatcher();
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String uri = request.getRequestURI();
            // 匹配/course/xxx 路径提取courseId
            if (antPathMatcher.match("/course/{courseId}", uri)) {
                Map<String, String> pathVars = antPathMatcher.extractUriTemplateVariables("/course/{courseId}", uri);
                Long courseId = Long.parseLong(pathVars.get("courseId"));
                // 权限校验不通过返回403
                if (!permissionChecker.hasCourseRole(courseId, "TEACHER", "STUDENT")) {
                    response.sendError(HttpServletResponse.SC_FORBIDDEN);
                    return false;
                }
                // 把角色存入request供后续业务使用
                request.setAttribute("userCourseRole", permissionChecker.getUserCourseRole(courseId));
            }
            return true;
        }
    }
    
  • 在Spring MVC配置类中注册拦截器,指定拦截路径即可。

视图层适配

如果不想做多视图拆分,也可以把用户的课程角色存入Model,在JSP中通过标签判断显示不同模块:

<c:if test="${isTeacher}">
    <!-- 教师专属的公告发布、成员管理模块 -->
    <div class="teacher-operation">
        <button onclick="publishNotice()">发布公告</button>
    </div>
</c:if>

内容的提问来源于stack exchange,提问作者Delsh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 03:15:02