如何在 Spring Security 中自定义权限表达式
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在 Spring Security 中自定义权限表达式相关的知识,希望对你有一定的参考价值。
参考技术A 在前面的文章中,松哥已经和小伙伴们聊了 Spring Security 中的权限表达式了,还没看过的小伙伴们可以先看下,本文将在前文的基础上继续完善:经过上篇文章的学习,小伙伴们已经知道了,在 Spring Security 中,@PreAuthorize、@PostAuthorize 等注解都是支持 SpEL 表达式的。
在 SpEL 表达式中,如果上来就直接写要执行的方法名,那么就说明这个方法是 RootObject 对象中的方法,如果要执行其他对象的方法,那么还需要写上对象的名字,例如如下两个例子:
上面这个例子中,表达式中的方法是 hasAuthority,没有写对象名,那么就说明这个方法是 SpEL 中 RootObject 对象中的方法。
上面这个例子中,权限注解中的表达式方法是 @ss.hasPermi('monitor:operlog:list') ,其中 ss 是指 Spring 容器中的一个对象名,hasPermi 则是这个对象中的方法。
好啦,经过前面文章的学习,这些基本知识大家都已经掌握了。
其实上面给出来的第二个例子就是一个自定义的例子。
不过,这种自定义方式太自由了,自由到没有在 Spring Security 架构内完成这件事。所以,今天我想和小伙伴们聊一聊,如何在不使用第三方对象的情况下,来自定义一个权限判断的表达式。
首先小伙伴们知道,我们在 @PreAuthorize 注解中使用的不用加对象名就能调用的权限方法,如 hasAuthority 、 hasPermission 、 hasRole 、 hasAnyRole 等,基本上都是由 SecurityExpressionRoot 及其子类提供的,准确来说是由 MethodSecurityExpressionRoot 类提供的。
MethodSecurityExpressionRoot 类实际上继承自 SecurityExpressionRoot,只不过增加了过滤对象以及返回值对象。我们来看下 MethodSecurityExpressionRoot 的方法摘要:
再来看看 SecurityExpressionRoot 中的方法:
这些就是 RootObject 对象中的所有方法了,也是我们能够在 @PreAuthorize 注解中使用的所有方法了。
那么现在想在已有方法上继续扩展新方法,那么我们可以通过自定义类继承自 SecurityExpressionRoot 对象,扩展这个 RootObject 对象,在该对象中继续添加新的方法,进而实现自定义权限表达式。
好啦,说干就干,开搞!
本文的案例在前文的基础上继续完成,所以这里我就不从头开始写了。
首先我们自定义一个类继承自 SecurityExpressionRoot 并实现 MethodSecurityExpressionOperations 接口(本来直接继承自 MethodSecurityExpressionRoot 即可,但是因为这个类不是 public 的,没法继承,所以我们就实现 MethodSecurityExpressionOperations 接口即可):
加了 @Override 注解的方法,都是普普通通的常规方法,没啥好说的。我们自己主要实现了三个方法,分别是:
这里边的逻辑我就不啰嗦了,都是基本的 Java 语法而已。
另外,用 AntPathMatcher 做比对是为了支持通配符,这个在上篇文章中已经说过了,这里不再赘述。
Spring Security 中,MethodSecurityExpressionRoot 的配置是通过 DefaultMethodSecurityExpressionHandler 来完成的,现在我们自定义了 CustomSecurityExpressionRoot,那也得有一个 Handler 来配置 CustomSecurityExpressionRoot,所以,再来一个类继承自 DefaultMethodSecurityExpressionHandler,如下:
在 createSecurityExpressionRoot 方法中创建一个 CustomSecurityExpressionRoot 对象,对象的 TrustResolver、权限评估器以及角色层级等,统统都用默认的方案即可。
配置完成后,再配置一下 CustomMethodSecurityExpressionHandler 这个 Bean 即可,如下:
好啦,这就注入成功了。
接下来,我们就可以在权限注解中使用这个自定义的方法了:
这个自定义权限表达式的思路,说到底还是在 Spring Security 体系中玩,个人感觉这种方式更合理一些。
在 TienChin 项目中,松哥也将按照这种思路去改造 RuoYi-Vue 脚手架。届时在 TienChin 项目视频中,我再和大伙细聊,对视频感兴趣的小伙伴,戳这里:TienChin 项目配套视频来啦。
如何在 Spring Boot 1.4 中自定义 Jackson
【中文标题】如何在 Spring Boot 1.4 中自定义 Jackson【英文标题】:How to customise Jackson in Spring Boot 1.4 【发布时间】:2017-01-08 20:48:48 【问题描述】:我一直无法找到如何在 spring boot 1.4 中使用 Jackson2ObjectMapperBuilderCustomizer.java 来自定义 Jackson 的功能的示例。
在 boot 1.4 中自定义 Jackson 的文档 - https://docs.spring.io/spring-boot/docs/1.4.x/reference/htmlsingle/#howto-customize-the-jackson-objectmapper
我的配置有效,但我不确定这是否是使用 Jackson2ObjectMapperBuilderCustomizer.java
自定义对象映射器的正确方法@Configuration
public class JacksonAutoConfiguration
@Autowired
private Environment env;
@Bean
public Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder(
List<Jackson2ObjectMapperBuilderCustomizer> customizers)
Jackson2ObjectMapperBuilder builder = configureObjectMapper();
customize(builder, customizers);
return builder;
private void customize(Jackson2ObjectMapperBuilder builder,
List<Jackson2ObjectMapperBuilderCustomizer> customizers)
for (Jackson2ObjectMapperBuilderCustomizer customizer : customizers)
customizer.customize(builder);
private Jackson2ObjectMapperBuilder configureObjectMapper()
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
List<String> activeProfiles = asList(env.getActiveProfiles());
if (activeProfiles.contains(SPRING_PROFILE_DEVELOPMENT))
builder.featuresToEnable(SerializationFeature.INDENT_OUTPUT);
return builder;
为了提供一些上下文,这个类位于我自己的 REST 服务 spring 启动项目中,它只是自动配置一些东西,比如 ControllerAdvice 和一些像上面这样的琐碎功能。
所以我的目标是扩展 Jackson 配置,而不是覆盖 boot 或其他包提供的任何配置。
【问题讨论】:
【参考方案1】:要自定义 Spring Boot 已经预配置的 Jackson ObjectMapper
,我能够做到这一点(这里的示例是添加自定义反序列化器)。
配置类:
@SpringBootConfiguration
public class Application
@Autowired
private BigDecimalDeserializer bigDecimalDeserializer;
...
@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomBigDecimalDeserialization()
return new Jackson2ObjectMapperBuilderCustomizer()
@Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder)
jacksonObjectMapperBuilder.deserializerByType(BigDecimal.class, bigDecimalDeserializer);
;
...
还有我的自定义反序列化器,以展示 Spring 是如何拾取它的:
@Component
public class BigDecimalDeserializer extends StdDeserializer<BigDecimal>
public BigDecimalDeserializer()
super(BigDecimal.class);
@Override
public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
...
...
【讨论】:
看准了!这是我最初尝试做的,但一定是做错了什么,谢谢。【参考方案2】:这取决于你想要做什么。
如果除了默认执行的自定义之外,您还想进行一些自定义,那么您应该创建自己的 Jackson2ObjectMapperBuilderCustomizer
实现并将其公开为 bean。您目前拥有的是一个更复杂的版本。与其注入定制器然后自己调用它们,不如创建自己的定制器 bean,Boot 会为您调用它。
如果您想完全控制并关闭所有 Boot 的自定义设置,请创建一个 Jackson2ObjectMapperBuilder
或 ObjectMapper
bean 并根据需要进行配置。构建器方法是首选,因为此构建器还用于配置由其他组件(如 Spring Data REST)创建的 ObjectMapper。
查看您的代码并退后一步,您可以通过使用特定于配置文件的配置文件(例如 application-dev.properties
)来启用 Jackson 输出的缩进,从而更简单地进行配置。您可以阅读更多关于 here 的信息。
【讨论】:
谢谢这是我最初所做的,但它似乎没有效果。我明天会发布我的代码,也许你可以告诉我哪里没有错。至于您通过属性文件配置它的建议,我已经更新了我的问题,以提供更多关于我如何使用此配置类的上下文。【参考方案3】:只需创建一个ObjectMapper
bean:
@Bean
ObjectMapper objectMapper()
return Jackson2ObjectMapperBuilder
.json()
.featuresToEnable(MapperFeature.DEFAULT_VIEW_INCLUSION)
.build();
【讨论】:
抱歉,我可能更清楚地表明我实际上是在扩展对象映射器功能。而您的建议实际上会覆盖任何 ObjectMapper bean,例如默认的一个 spring boot 配置 这对于 Spring Boot 来说不是很好的方法,因为可以有多个 jackson 定制器,并且返回构建的对象映射器实例使它们完全无用。以上是关于如何在 Spring Security 中自定义权限表达式的主要内容,如果未能解决你的问题,请参考以下文章
使用 AuthenticationFailureHandler 在 Spring Security 中自定义身份验证失败响应