Spring Boot 简单接口角色授权检查实现

一、背景与目标

在Spring Boot应用开发中,接口级别的权限控制是系统安全的重要组成部分。本文将介绍一种简单直接的接口角色授权检查实现方案,适合快速开发和安全合规检查场景。

二、技术方案概述

本方案采用自定义注解+拦截器的方式实现,具有以下特点:

  • 零依赖(不引入Spring Security等重型框架)

  • 代码简洁(总共不到100行核心代码)

  • 易于理解和使用

  • 满足基本的安全检查要求

三、完整实现步骤

1. 创建权限注解

java 复制代码
import java.lang.annotation.*;

/**
 * 权限检查注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiredPermission {
    String value(); // 权限标识符,如"user:add"
}

2. 实现权限拦截器

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 权限检查拦截器
 */
@Component
public class PermissionInterceptor implements HandlerInterceptor {
    
    // 可以注入需要的服务(如用户服务)
    @Autowired
    private UserService userService;
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) throws Exception {
        
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        
        // 获取方法上的权限注解
        RequiredPermission permission = method.getAnnotation(RequiredPermission.class);
        if (permission == null) {
            return true; // 无权限注解则放行
        }
        
        String requiredPermission = permission.value();
        String token = request.getHeader("Authorization");
        
        // 实际项目中应从token解析用户信息,这里简化为直接判断
        boolean hasPermission = checkPermission(token, requiredPermission);
        
        if (!hasPermission) {
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.getWriter().write("Access denied: Required permission - " + requiredPermission);
            return false;
        }
        
        return true;
    }
    
    private boolean checkPermission(String token, String requiredPermission) {
        // 这里写死检查逻辑,实际项目应从数据库或缓存获取用户权限
        if ("admin-token".equals(token)) {
            return true; // 管理员有所有权限
        } else if ("user-token".equals(token)) {
            return !"user:add".equals(requiredPermission); // 普通用户不能新增用户
        }
        return false;
    }
}

3. 注册拦截器

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Autowired
    private PermissionInterceptor permissionInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(permissionInterceptor)
                .addPathPatterns("/api/**"); // 拦截/api开头的请求
    }
}

4. 在Controller中使用

java 复制代码
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/user")
public class UserController {
    
    @PostMapping
    @RequiredPermission("user:add")
    public String addUser() {
        return "User added successfully";
    }
    
    @GetMapping
    @RequiredPermission("user:view")
    public String listUsers() {
        return "User list";
    }
    
    @PutMapping("/{id}")
    @RequiredPermission("user:edit")
    public String updateUser(@PathVariable Long id) {
        return "User updated";
    }
    
    @DeleteMapping("/{id}")
    @RequiredPermission("user:delete")
    public String deleteUser(@PathVariable Long id) {
        return "User deleted";
    }
}

四、方案特点与优势

  1. 简单直接:无需复杂配置,快速实现权限控制

  2. 灵活可控:可以自由定义权限标识和检查逻辑

  3. 易于扩展:可以方便地替换为从数据库检查权限

  4. 符合RESTful:返回标准的HTTP状态码(403 Forbidden)

  5. 低侵入性:只需要添加注解,不影响业务逻辑代码

五、进阶优化方向

  1. 结合JWT:从token中解析用户角色和权限

  2. 缓存优化:缓存用户权限数据,减少数据库查询

  3. 动态权限:实现权限的动态配置和管理

  4. 日志记录:记录权限验证失败的访问尝试

  5. 白名单:添加无需权限检查的接口白名单

六、测试验证

可以使用Postman或curl进行测试:

bash 复制代码
# 管理员可以访问所有接口
curl -X POST -H "Authorization: admin-token" http://localhost:8080/api/user

# 普通用户不能访问添加接口
curl -X POST -H "Authorization: user-token" http://localhost:8080/api/user
# 返回: Access denied: Required permission - user:add

# 普通用户可以访问查看接口
curl -X GET -H "Authorization: user-token" http://localhost:8080/api/user
# 返回: User list

七、总结

本文介绍的Spring Boot接口权限控制方案虽然简单,但包含了权限控制的核心要素,能够满足基本的安全需求。对于快速开发和小型项目来说,这是一个轻量级且有效的解决方案。对于更复杂的企业级应用,建议在此基础上进行扩展或考虑使用Spring Security等专业安全框架。

相关推荐
星栈10 分钟前
MCP 从 stdio 迁到 SSE,踩了 5 个传输层坑
人工智能·后端·架构
Conan在掘金12 分钟前
鸿蒙报错速查:struct 里嵌 enum 声明就炸,根因 + 真解法
后端
captain37625 分钟前
多线程线程安全问题
java·java-ee
CoderYanger36 分钟前
A.每日一题:1979. 找出数组的最大公约数
java·程序人生·算法·leetcode·面试·职场和发展·学习方法
paopaokaka_luck44 分钟前
基于Springboot3+Vue3的高校选课系统(AI选课助手、协同过滤算法、分享到微博、扣扣、Echarts图形化分析)
网络·spring boot·网络协议·echarts
灵极海1 小时前
LangChain4j RAG 实战完整指南:从入门到踩坑
java·langchain
yaoxin5211231 小时前
476. Java 反射 - 调用方法
java·开发语言
回家路上绕了弯1 小时前
Java双数据源实战全指南:Spring Boot多数据源配置、原理与踩坑避坑
后端
神奇小汤圆1 小时前
Redis主从切换后,旧主恢复竟触发全量同步?——我猜错了,原因比想象中更严谨
后端
JoyT1 小时前
滚动MAD与孤立森林在时序异常检测中的协同应用
后端