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

Spring Boot中如何实现带参数的控制器方法权限校验注解?

实现Spring Boot控制器方法的权限校验注解

我来帮你一步步搞定这个需求,在Spring Boot环境下结合自定义注解和拦截器就能完美实现,具体步骤如下:

1. 完善自定义注解@ValidateAction的定义

首先确保你的注解符合Java规范,指定作用目标为方法且运行时可被反射获取:

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateAction {
    String resource();
    String action();
}

(使用时写成@ValidateAction(resource = "resource", action = "release"),这种带属性名的写法更清晰规范)

2. 在拦截器中获取注解参数并校验权限

修改你已有的请求拦截器,在preHandle方法里定位到当前请求对应的Controller方法,提取注解参数后调用授权服务器做权限校验:

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.client.RestTemplate;

public class PermissionInterceptor implements HandlerInterceptor {

    private final RestTemplate restTemplate;

    // 通过构造注入RestTemplate用于调用授权服务器
    public PermissionInterceptor(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 先判断当前处理器是否是Controller方法
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 获取方法上的@ValidateAction注解
            ValidateAction validateAction = handlerMethod.getMethodAnnotation(ValidateAction.class);
            
            if (validateAction != null) {
                // 提取注解里的资源和操作参数
                String resource = validateAction.resource();
                String action = validateAction.action();
                
                // 从请求头取出OAuth令牌(通常格式是Authorization: Bearer xxx)
                String authHeader = request.getHeader("Authorization");
                if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                    throw new AccessDeniedException("缺少有效访问令牌");
                }
                String accessToken = authHeader.substring(7);
                
                // 调用授权服务器校验权限
                boolean hasPermission = checkPermission(accessToken, resource, action);
                
                if (!hasPermission) {
                    throw new AccessDeniedException("你没有执行该操作的权限");
                }
            }
        }
        // 没有注解或者校验通过,放行请求
        return true;
    }

    // 封装调用授权服务器的逻辑
    private boolean checkPermission(String accessToken, String resource, String action) {
        // 这里替换成你授权服务器的实际校验接口地址
        String checkUrl = "http://your-auth-server/api/permission/check";
        // 构造请求参数DTO
        PermissionCheckReq req = new PermissionCheckReq(accessToken, resource, action);
        // 发送请求并获取校验结果
        Boolean result = restTemplate.postForObject(checkUrl, req, Boolean.class);
        
        // 处理空指针情况,默认返回无权限
        return result != null && result;
    }

    // 内部类:权限校验请求参数
    private static class PermissionCheckReq {
        private String accessToken;
        private String resource;
        private String action;

        public PermissionCheckReq(String accessToken, String resource, String action) {
            this.accessToken = accessToken;
            this.resource = resource;
            this.action = action;
        }

        // 省略getter/setter
    }
}

3. 注册拦截器到Spring容器

最后要把拦截器配置到Spring Boot的WebMvc中,让它生效:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Bean
    public PermissionInterceptor permissionInterceptor(RestTemplate restTemplate) {
        return new PermissionInterceptor(restTemplate);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 指定拦截的路径,比如拦截所有/api开头的请求,可根据你的业务调整
        registry.addInterceptor(permissionInterceptor(restTemplate()))
                .addPathPatterns("/**");
    }
}

4. 在Controller方法上使用注解

现在就可以按照你期望的方式使用注解了:

@RequestMapping("/release")
@ValidateAction(resource = "resource", action = "release")
public ResponseEntity releaseSoftware(Request request){
    // 你的业务逻辑代码
}

这样当请求到达该方法时,拦截器会自动提取注解参数,携带OAuth令牌调用授权服务器校验权限;如果校验不通过,会直接抛出AccessDeniedException,Spring Security会自动处理这个异常并返回对应的权限错误响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:18:01