想要控制好权限,这八个注解必须知道!

2023年 8月 10日 63.7k 0

在码猿慢病云管理系统采用的是Spring Cloud 集成Spring Security OAuth2的方式实现认证、鉴权,其中涉及到的一个重要问题则是数据权限的过滤,今天就来介绍一下实现的方案。

在之前的文章中曾经介绍过通过自定义的三个注解 @RequiresLogin、 @RequiresPermissions 、 @RequiresRoles 实现微服务的鉴权其实就是参考Spring Security 内置的注解实现,有想要了解的请看:3 个注解,优雅的实现微服务鉴权

在介绍数据权限之前,先来看下Spring Security 中内置的8个权限注解,只有理解了这8个注解,对于理解码猿慢病云管理系统中的实现方案就非常easy了。

Spring Security 内置的权限注解是将鉴权下放到各个微服务,想要了解在网关处统一鉴权处理的请看之前分享的文章:实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式统一认证授权!

Spring Security 中的权限注解

Spring Security 中支持多种数据权限注解,若想使用内置的注解,首先需要通过@EnableGlobalMethodSecurity这个注解开启权限注解的支持,代码如下:

/**
 * @author 公众号:码猿技术专栏
 * 自定义资源服务注解
 * {@link com.code.ape.codeape.common.security.annotation.EnableCodeapeResourceServer}
 */
@Documented
@Inherited
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import({ CodeapeResourceServerAutoConfiguration.class, CodeapeResourceServerConfiguration.class })
public @interface EnableCodeapeResourceServer {}

在码猿慢病云管理系统中是将Spring Security集成为一个Spring Boot Starter,因此需要一个直接开启对于Spring Security的支持,EnableCodeapeResourceServer是自定义的资源服务注解,便于一键导入资源服务配置,只要是资源服务,只需要在资源服务配置类上添加这个注解即可。

比如设备服务(codeape-device-biz)的启动类如下:

图片图片

如果是直接集成Spring Security ,那么直接在配置类标注@EnableGlobalMethodSecurity这个注解也是一样效果,代码如下:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}

@EnableGlobalMethodSecurity注解的三个属性如下:

  • prePostEnabled:设置为true,将会开启 Spring Security 提供的四个权限注解,@PostAuthorize、@PostFilter、@PreAuthorize 以及 @PreFilter,这四个注解支持权限表达式,支持 SpEL,功能比较丰富。
  • securedEnabled:设置为true,将会开启 Spring Security 提供的 @Secured 注解,该注解不支持权限表达式。
  • jsr250Enabled:设置为true,将会开启 JSR-250 提供的注解,主要包括 @DenyAll、@PermitAll 以及 @RolesAllowed 三个注解,这些注解也不支持权限表达式。

以上的8个注解总结如下:

  • @PostAuthorize:在目标方法执行之后进行权限校验。
  • @PostFilter:在目标方法执行之后对方法的返回结果进行过滤。
  • @PreAuthorize:在目标方法执行之前进行权限校验。
  • @PreFilter:在目标方法执行之前对方法参数进行过滤。
  • @Secured:访问目标方法必须具备相应的角色。
  • @DenyAll:拒绝所有访问。
  • @PermitAll:允许所有访问。
  • @RolesAllowed:访问目标方法必须具备相应的角色。
  • 其实在日常开发中使用前四个注解已经完全够用,且支持灵活的SPEL权限表达式,方便定制。因此只需要设置prePostEnabled = true

    权限注解使用

    接下来就来简单介绍一下这8个权限注解的使用。

    1. @PreAuthorize

    @PreAuthorize这个注解在方法执行之前进行安全校验,支持SPEL,比如在接口使用代码如下:

    @RestController
    @RequestMapping
    public class HelloService {
        @PreAuthorize("hasRole('IN_HOS_NURSE')")
        @GetMapping
        public String hello() {
            return "hello";
        }
    }

    @PreAuthorize("hasRole('IN_HOS_NURSE')")代码含义则是只有拥有住院护士的角色的用户才能访问这个接口。这里用到了hasRole这个权限表达式,表示拥有某个角色

    2. @PreFilter

    @PreFilter这个注解主要是对参数进行过滤,其中两个属性如下:

    • value :SPEL表达式校验
    • filterTarget:多个参数的情况下,指定对某个参数校验

    使用如下:

    @RestController
    @RequestMapping
    public class HelloService {
        @PreFilter(value = "obj.id!=1",filterTarget = "users")
        @GetMapping
        public String hello(List obj,Integer a) {
            return "hello";
        }
    }

    3. @PostAuthorize

    @PostAuthorize是在方法执行之后进行数据校验,平常所有的数据校验一般是在方法执行之前,所以一般结合@PreAuthorize使用。

    PostAuthorize中内置了一个returnObject返回值,对方法的返回值校验,使用如下:

    @RestController
    @RequestMapping
    public class HelloService {
        @PostAuthorize(value = "returnObject.id==1")
        @GetMapping
        public Obj hello(List obj,Integer a) {
            return "hello";
        }
    }

    这个接口的返回值的id必须等于1才会通过,否则将会抛出异常。

    4. @PostFilter

    @PostFilter 注解是在目标方法执行之后,对目标方法的返回结果进行过滤,该注解中包含了一个内置对象 filterObject,表示目标方法返回的集合/数组中的具体元素:

    @RestController
    @RequestMapping
    public class HelloService {
        @PostFilter(value = "filterObject.id==1")
        @GetMapping
        public Obj hello(List obj,Integer a) {
            return "hello";
        }
    }

    5. @Secured

    @Secured 注解也是 Spring Security 提供的权限注解,不同于前面四个注解,该注解不支持权限表达式,只能做一些简单的权限描述。

    使用如下:

    @RestController
    @RequestMapping
    public class HelloService {
        @Secured({"ROLE_IN_HOS_NURSE","ROLE_IN_HOS_DOC"})
        @GetMapping
        public Obj hello(List obj,Integer a) {
            return "hello";
        }
    }

    这段代码表示只有当前用户拥有住院护士、住院医生的权限才能访问这个接口。

    @Secured能够做的,@PreAuthorize也都能做,且给的更多!

    6. @DenyAll

    @DenyAll 是 JSR-250 提供的方法注解,顾名思义,拒绝所有请求。

    @RestController
    @RequestMapping
    public class HelloService {
        @DenyAll
        @GetMapping
        public String hello() {
            return "hello";
        }
    }

    7. @PermitAll

    @PermitAll 也是 JSR-250 提供的方法注解,顾名思义,允许所有访问!

    @RestController
    @RequestMapping
    public class HelloService {
        @PermitAll
        @GetMapping
        public String hello() {
            return "hello";
        }
    }

    8. @RolesAllowed

    @RolesAllowed 也是 JSR-250 提供的注解,可以添加在方法上或者类上,当添加在类上时,表示该注解对类中的所有方法生效;如果类上和方法上都有该注解,并且起冲突,则以方法上的注解为准。

    @RestController
    @RequestMapping
    public class HelloService {
        @RolesAllowed({"IN_HOS_NURSE","IN_HOS_DOC"})
        @GetMapping
        public Obj hello(List obj,Integer a) {
            return "hello";
        }
    }

    这段代码表示只有当前用户拥有住院护士、住院医生的权限才能访问这个接口。

    根据上述的介绍,大致理解了这8个注解,实际项目中建议使用@PostAuthorize、@PostFilter、@PreAuthorize 以及 @PreFilter这四个注解,完全够用了!

    慢病云管理系统的实践

    在码猿慢病云管理系统中使用的权限注解是@PreAuthorize,在接口执行之前对数据权限进行校验。

    比如住院服务codeape-inhos-biz中的分页查询住院患者接口如下:

    图片图片

    这里的@PreAuthorize("@pms.hasPermission('inhos_patinfohot_get')" )则是对用户的权限进行拦截校验,只有拥有inhos_patinfohot_get权限的用户才能访问这个接口。

    而这里是直接通过SPEL表达式调用IOC容器中的方法进行拦截校验,代码如下:

    com.code.ape.codeape.common.security.component.PermissionService#hasPermission

    图片图片

    逻辑很简单,从SecurityContext中获取用户的权限和指定的权限进行比较,校验通过则返回true。

    总结

    本篇文章介绍了Spring Security 中内置的8个权限注解以及码猿慢病云管理系统中的实践,这个权限注解的使用是必须将权限下放到微服务鉴权才能用到,如果你的系统是在网关处统一鉴权则用不到。

    码猿慢病云管理系统已经在星球中陆续更新,目前更新内容如下:

    前言
         01 项目架构+业务介绍
         02 三方组件介绍
         03 服务端项目部署
         04 前端项目部署
         05 多租户架构设计
         06 医疗系统中的权限如何设计?
         07 项目搭建
         08 关掉验证码登录
         09 开发平台自动生成业务代码
    认证鉴权
         01 认证登录生成token
         02 token检验、鉴权
         03 token有效期设置
         04 刷新token
         05 检查token
         06 服务中如何获取当前登录用户信息?
         07 接口对外暴露
         08 接口只允许内部调用怎么处理?
         09 如何实现token中继?
         10 当前登录用户身份信息如何异步传递?
         11 科室权限如何定一个注解自动注入?
         12 一个注解防止接口重复提交
         13 8个权限注解玩转鉴权
    业务
         01 科室管理
         02 医院管理
         03 角色管理
         04 菜单+权限管理

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论