想要控制好权限,这8个注解必须知道!
大家好,我是不才陈某~
在码猿慢病云管理系统采用的是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> 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> 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> 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> 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> 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个权限注解以及码猿慢病云管理系统中的实践,这个权限注解的使用是必须将权限下放到微服务鉴权才能用到,如果你的系统是在网关处统一鉴权则用不到。
文章转载自公众号: 码猿技术专栏