这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战
写在前面
各位小伙伴。 到目前为止,我们已经系统介绍了 Spring Security 中的认证和授权过程。但是请注意,我们讨论的对象是 Web 应用程序,也就是说认证和授权的资源是一系列的 HTTP 端点。那么如果我们开发的不是一个 Web 应用程序呢?认证和授权还能否发挥作用呢?答案是肯定的。
今天我们就来讨论针对方法级别的安全访问策略,确保一个普通应用程序中的每个组件都能具备安全性保障。
这里多唠叨一句,欢迎大家查看我的专栏,目前正在进行的Security专栏和队列并发专栏,设计模式专题(已完结)
全局方法安全机制
明确方法级别的安全机制之前,我们先来剖析一个典型的应用程序具备的各层组件。以 Spring Boot 应用程序为例,我们可以采用经典的分层架构,即将应用程序分成 Controller 层、Service 层和 Repository 层。请注意,三层架构中的 Service 层组件可能还会调用其他的第三方组件。
请注意,默认情况下 Spring Security 并没有启用全局方法安全机制。因此,想要启用这个功能,我们需要使用@EnableGlobalMethodSecurity 注解。正如本专栏前面案例所展示的,一般的做法是创建一个独立的配置类,并把这个注解添加在配置类上,如下所示:
1 | java复制代码@Configuration |
方法调用过滤本质上类似于过滤器机制,也可以分为 PreFilter 和 PostFilter 两大类。其中预过滤(PreFilter)用来对该方法的参数进行过滤,从而获取其参数接收的内容,而后过滤(PostFilter)则用来判断调用者可以在方法执行后从方法返回结果中接收的内容。
请注意,在使用 @EnableGlobalMethodSecurity 注解时,我们设置了“prePostEnabled”为 true,意味着我们启用了 Pre/PostAuthorization 注解,而默认情况下这些注解也是不生效的。同时,我们也需要知道,在 Spring Security 中为实现全局方法安全机制提供了三种实现方法,除了 Pre/PostAuthorization 注解之外.
在本专栏中,我们只讨论最常用的 Pre/PostAuthorization 注解,下面我们来看具体的使用方法。
使用注解实现方法级别授权
针对方法级别授权,Spring Security 提供了 @PreAuthorize 和 @PostAuthorize 这两个注解,分别用于预授权和后授权。
今天我们先来看@PreAuthorize 下期再看 @PostAuthorize
@PreAuthorize 注解
先来看 @PreAuthorize 注解的使用场景。假设在一个基于 Spring Boot 的 Web 应用程序中,存在一个 Web 层组件 OrderController.
该 Controller 会调用 Service 层的组件 OrderService。我们希望对访问 OrderService 层中方法的请求添加权限控制能力,即只有具备“DELETE”权限的请求才能执行 OrderService 中的 deleteOrder() 方法,而没有该权限的请求将直接抛出一个异常,如下图所示(Service 层组件预授权示意图):
显然,上述流程针对的是预授权的应用场景,因此我们可以使用 @PreAuthorize 注解,
该注解定义如下:
1 | java复制代码@Target({ ElementType.METHOD, ElementType.TYPE }) |
要想在应用程序中集成 @PreAuthorize 注解,我们可以创建如下所示的安全配置类,在这个配置类上我们添加了 @EnableGlobalMethodSecurity 注解:
1 | java复制代码@Configuration |
这里,我们创建了两个用户“yn1”和“yn2”,分别具备“WRITE”和“DELETE”权限。然后,我们实现 OrderService 的 deleteOrder() 方法,如下所示:
1 | java复制代码@Service |
可以看到,这里使用了 @PreAuthorize 注解来实现预授权。在该注解中,我们通过熟悉的 hasAuthority(‘DELETE’) 方法来判断请求是否具有“DELETE”权限。
上面介绍的这种情况比较简单,我们再来看一个比较复杂的场景,该场景与用户认证过程进行整合。
假设在 OrderService 中存在一个 getOrderByUser(String user) 方法,而出于系统安全性的考虑,我们希望用户只能获取自己创建的订单信息,也就是说我们需要校验通过该方法传入的“user”参数是否为当前认证的合法用户。这种场景下,我们就可以使用 @PreAuthorize 注解:
1 | java复制代码@PreAuthorize("#name == authentication.principal.username") |
这里我们将输入的“user”参数与通过 SpEL 表达式从安全上下文中获取的“authentication.principal.username”进行比对,如果相同就执行正确的方法逻辑,反之将直接抛出异常。
好,今天我们就讲这一个小点,明天我们讲另一个注解 慢慢学。加油!
总结
这一讲我们关注的重点从 HTTP 端点级别的安全控制转换到了普通方法级别的安全控制。Spring Security 内置了一组非常实用的注解,方便开发人员实现全局方法安全机制,包括用于实现方法级别授权的 @PreAuthorize 和 @PostAuthorize 注解(下期讲)
弦外之音
感谢你的阅读,如果你感觉学到了东西,您可以点赞,关注。也欢迎有问题我们下面评论交流
加油! 我们下期再见!
给大家分享几个我前面写的几篇骚操作
本文转载自: 掘金