Spring Boot 注解实战:30 行代码搞定字段级权限控制

boyanx2个月前技术教程18

Spring Boot 注解实战:30 行代码搞定字段级权限控制

在企业级应用开发中,权限控制是一个绕不开的话题。从粗粒度的 URL 级权限,到细粒度的方法级权限,再到今天要聊的字段级权限,我们的安全边界在不断收紧。

字段级权限控制的需求场景其实很常见:比如同样一个用户信息接口,普通用户只能看到昵称和头像,管理员却能看到手机号和邮箱,而超级管理员还能看到更多敏感信息。

传统的做法可能是为不同角色写不同的 DTO 和接口,这种方式不仅冗余,还难以维护。今天我要分享的是如何利用 Spring Boot 的注解特性,用更优雅的方式实现字段级权限控制。

实现思路

我们的核心思路是在序列化阶段对响应数据进行拦截,根据当前用户的角色决定哪些字段可以被序列化并返回给前端。主要涉及三个关键组件:

  1. 自定义注解:标记需要进行权限控制的字段及所需角色
  2. AOP 切面:在接口返回前对结果进行处理
  3. 序列化过滤器:根据权限动态过滤字段

代码实现

首先,我们需要定义一个用于标记字段权限的注解:

java

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldPermission {
    // 允许访问的角色列表
    String[] roles() default {};
    
    // 当没有权限时显示的默认值
    String defaultValue() default "*****";
}

接下来,创建一个 AOP 切面,用于在控制器方法返回结果后进行处理:

java

@Aspect
@Component
public class FieldPermissionAspect {
    @Autowired
    private UserContext userContext; // 自定义用户上下文,用于获取当前用户角色
    
    @AfterReturning(pointcut = "@annotation(org.springframework.web.bind.annotation.RequestMapping)", 
                   returning = "result")
    public Object handleFieldPermission(Object result) {
        if (result == null) return null;
        
        // 获取当前用户角色
        String currentRole = userContext.getCurrentUserRole();
        
        // 使用自定义序列化器处理结果
        return FieldPermissionSerializer.serialize(result, currentRole);
    }
}

然后是核心的序列化过滤器实现:

java

public class FieldPermissionSerializer {
    public static Object serialize(Object obj, String currentRole) {
        if (obj == null) return null;
        
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept(
            new HashSet<>(getAllowedFields(obj.getClass(), currentRole))
        );
        
        objectMapper.addMixIn(obj.getClass(), getFilterMixIn(obj.getClass(), filter));
        
        try {
            String json = objectMapper.writeValueAsString(obj);
            return objectMapper.readValue(json, obj.getClass());
        } catch (Exception e) {
            throw new RuntimeException("字段权限过滤失败", e);
        }
    }
    
    private static List<String> getAllowedFields(Class<?> clazz, String currentRole) {
        List<String> allowedFields = new ArrayList<>();
        
        // 遍历所有字段,检查权限
        for (Field field : clazz.getDeclaredFields()) {
            FieldPermission permission = field.getAnnotation(FieldPermission.class);
            if (permission == null) {
                // 没有注解的字段默认允许访问
                allowedFields.add(field.getName());
            } else {
                // 检查当前角色是否有权限访问该字段
                if (Arrays.asList(permission.roles()).contains(currentRole)) {
                    allowedFields.add(field.getName());
                }
            }
        }
        
        return allowedFields;
    }
    
    // 创建动态混入类用于过滤
    private static Class<?> getFilterMixIn(Class<?> clazz, SimpleBeanPropertyFilter filter) {
        FilterProvider filterProvider = new SimpleFilterProvider()
            .addFilter(clazz.getName(), filter);
            
        // 具体实现略...
    }
}

最后,我们就可以在实体类中使用这个注解了:

java

public class User {
    private Long id;
    private String username;
    private String nickname;
    
    @FieldPermission(roles = {"ADMIN", "SUPER_ADMIN"}, defaultValue = "*****")
    private String email;
    
    @FieldPermission(roles = {"SUPER_ADMIN"}, defaultValue = "*****")
    private String phone;
    
    // getter和setter...
}

优化与扩展

上面的实现提供了一个基础框架,在实际项目中我们还可以进行一些优化:

  1. 缓存字段权限信息,避免每次序列化都反射解析类
  2. 支持更复杂的权限表达式,而不仅仅是角色列表
  3. 对集合类型进行处理,确保列表中的每个对象都能正确过滤
  4. 结合 Spring Security,更紧密地集成到安全框架中

总结

通过注解 + AOP + 序列化过滤的组合,我们实现了一个轻量级但功能强大的字段级权限控制方案。这种方式的优点在于:

  • 侵入性低,只需在字段上添加注解
  • 灵活性高,可根据实际需求定制权限规则
  • 可维护性好,权限配置集中在注解上

这种思路不仅适用于权限控制,还可以扩展到数据脱敏、日志过滤等场景。希望今天的分享能给大家带来一些启发,欢迎在评论区交流你的想法!


感谢关注【AI码力】获取更多Java秘籍!

标签: superadmin

相关文章

Shiro中@RequiresAuthentication注解如何使用

1.使用。2.表示用户登陆成功才可得到用户信息:3.其它@RequiresAuthentication要求当前Subject已经在session中验证通过(验证当前用户是否登录:subject.isA...

初识sa-token,一行代码搞定登录授权

前言在java的世界里,有很多优秀的权限认证框架,如Apache Shiro、Spring Security 等等。这些框架背景强大,历史悠久,其生态也比较齐全。但同时这些框架也并非十分完美,在前后台...

Django干货知识分享,Admin管理工具

您好,欢迎来到这里学习Django框架,关注我会持续更新内容哦~如果本文对您有帮助,还请您点赞转发哦,谢谢!创建超级管理员python3 manage.py createsuperuser User...

大数据Hadoop之——Hadoop HDFS多目录磁盘扩展与数据平衡实战操作

一、概述hdfs 需要存写大量文件,有时磁盘会成为整个集群的性能瓶颈,所以需要优化 hdfs 存取速度,将数据目录配置多磁盘,既可以提高并发存取的速度,还可以解决一块磁盘空间不够的问题。Hadoop...

分享一款超轻量的kettle web端调度平台

#大数据#简介 Smart Kettle是针对上述企业的痛点,对kettle的 使用做了一些包装、优化,使其在web端也能具备 基础的kettle作业、转换的配置、调度、监控,能 在很大一定程度上协助...

【SpringBoot系列教程五】一文学会SpringSecurity

对于一些重要的操作,有些请求需要用户验明身份后才可以进行;有时候,可能需要与第三方公司合作,存在系统之间的交互,这时也需要验证合作方身份才能处理业务。这样做的意义在于保护自己的网站安全,避免一些恶意攻...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。