Spring 在@Preauthorize 中启动 属性
Spring Boot property in @Preauthorize
我正在设置一个 Spring 引导 (v1.2.6) 网络项目并使用 Spring 安全 (v3.2.8)。我发现 @PreAuthorize
注释非常方便,但我不知道是否有办法从注释中的 SpEL 中读取 Boot 的属性。我正在尝试这样做:
@PreAuthorize("mysecurity.permit")
随着 属性 在 application.yml 中声明:
mysecurity:
permit: true
但我得到了
Failed to evaluate expression 'mysecurity.permit'
我也尝试过 @mysecurity.permit
和 ${mysecurity.permit}
,结果相同。似乎可以在服务中声明一个方法并以 @service.isMySecurityPermited()
方式访问它,但是我很高兴知道我是否能够直接访问 属性。
这应该有效:
@Value("${mysecurity.permit}")
private Boolean permit;
然后使用:
@PreAuthorize(permit)
但您需要正确设置配置文件,以允许 Spring 访问它。在这里阅读:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
更新:
您是否为 属性 占位符配置了 bean?
例如:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/foo/app.properties</value>
</list>
</property>
</bean>
注释中使用的值必须是常量。它们在编译时进行评估,虽然它们可能会保留以供在运行时使用,但它们不是 re-evaluated。因此,您可以使用由 SpEL 计算的表达式,或者您可以编写一个在注释值中引用的辅助方法。
如果您查看 OnExpressionCondition 实现,您会注意到它获取传递给注释的值,在您的评论中链接的情况下,注释类似于 @ConditionalOnExpression("${server.host==localhost} or ${server.port==8080} ")
注释仅获取文本值,它不知道文本代表什么,它只知道它是一个字符串。正是在 OnExpressionCondition 中处理注释值时,String 值才有意义。他们获取 String 值并将其传递给 BeanExpressionResolver 进行解析。
因此,在基于 http://forum.spring.io/forum/spring-projects/security/100708-spel-and-spring-security-3-accessing-bean-reference-in-preauthorize 并将其传递给表达式处理器的 PreAuthorize 解决方案中,您应该能够使用 spring 的表达式语言来引用任何 bean 属性.
我目前无法对其进行测试,但从该线程来看,您似乎可以做类似的事情
@Component
public class MyBean {
@Value("${mysecurity.permit}")
private Boolean permit;
public boolean isPermitted() { return permit; }
@PreAuthorize( "@myBean.isPermitted()" )
public blah myMethod() {
// do stuff
}
}
这可能是一种计算表达式的通用方法,我想与您分享:
@Component("AuthorizationComponent")
public final class AuthorizationComponent {
private final static Logger logger = Logger.getLogger(AuthenticationUtils.class.getName());
private static SpelExpressionParser parser;
static {
parser = new SpelExpressionParser();
}
@Autowired
private Environment environment;
public boolean evaluateExpression(final String propertyKey) {
return checkExpression(environment.getProperty(propertyKey));
}
public static boolean checkExpression(String securityExpression) {
logger.info("Checking security expression [" + securityExpression + "]...");
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
Expression exp = parser.parseExpression(securityExpression);
SecurityExpressionRoot context = new CustomMethodSecurityExpressionRoot(authentication);
boolean result = exp.getValue(context, Boolean.class);
logger.info("Check result: " + result);
return result;
}
}
并且在yaml配置文件中你可以配置路径和授权表达式,像这样:
preAuthorize:
whatever:
post: hasRole('MY_ROLE') OR hasAuthority('MY_AUTHORITY')
然后你可以像这样在你的方法中使用它:
@PreAuthorize("@AuthorizationComponent.evaluateExpression('preAuthorize.whatevert.post')")
@RequestMapping(value = "", method = RequestMethod.POST)
public ResponseEntity<Void> addQuestion(@Valid @RequestBody BodyRestDTO bodyRestDTO){
//Code implementation
return new ResponseEntity<Void>(HttpStatus.CREATED);
}
我正在设置一个 Spring 引导 (v1.2.6) 网络项目并使用 Spring 安全 (v3.2.8)。我发现 @PreAuthorize
注释非常方便,但我不知道是否有办法从注释中的 SpEL 中读取 Boot 的属性。我正在尝试这样做:
@PreAuthorize("mysecurity.permit")
随着 属性 在 application.yml 中声明:
mysecurity:
permit: true
但我得到了
Failed to evaluate expression 'mysecurity.permit'
我也尝试过 @mysecurity.permit
和 ${mysecurity.permit}
,结果相同。似乎可以在服务中声明一个方法并以 @service.isMySecurityPermited()
方式访问它,但是我很高兴知道我是否能够直接访问 属性。
这应该有效:
@Value("${mysecurity.permit}")
private Boolean permit;
然后使用:
@PreAuthorize(permit)
但您需要正确设置配置文件,以允许 Spring 访问它。在这里阅读: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
更新: 您是否为 属性 占位符配置了 bean? 例如:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/foo/app.properties</value>
</list>
</property>
</bean>
注释中使用的值必须是常量。它们在编译时进行评估,虽然它们可能会保留以供在运行时使用,但它们不是 re-evaluated。因此,您可以使用由 SpEL 计算的表达式,或者您可以编写一个在注释值中引用的辅助方法。
如果您查看 OnExpressionCondition 实现,您会注意到它获取传递给注释的值,在您的评论中链接的情况下,注释类似于 @ConditionalOnExpression("${server.host==localhost} or ${server.port==8080} ")
注释仅获取文本值,它不知道文本代表什么,它只知道它是一个字符串。正是在 OnExpressionCondition 中处理注释值时,String 值才有意义。他们获取 String 值并将其传递给 BeanExpressionResolver 进行解析。
因此,在基于 http://forum.spring.io/forum/spring-projects/security/100708-spel-and-spring-security-3-accessing-bean-reference-in-preauthorize 并将其传递给表达式处理器的 PreAuthorize 解决方案中,您应该能够使用 spring 的表达式语言来引用任何 bean 属性.
我目前无法对其进行测试,但从该线程来看,您似乎可以做类似的事情
@Component
public class MyBean {
@Value("${mysecurity.permit}")
private Boolean permit;
public boolean isPermitted() { return permit; }
@PreAuthorize( "@myBean.isPermitted()" )
public blah myMethod() {
// do stuff
}
}
这可能是一种计算表达式的通用方法,我想与您分享:
@Component("AuthorizationComponent")
public final class AuthorizationComponent {
private final static Logger logger = Logger.getLogger(AuthenticationUtils.class.getName());
private static SpelExpressionParser parser;
static {
parser = new SpelExpressionParser();
}
@Autowired
private Environment environment;
public boolean evaluateExpression(final String propertyKey) {
return checkExpression(environment.getProperty(propertyKey));
}
public static boolean checkExpression(String securityExpression) {
logger.info("Checking security expression [" + securityExpression + "]...");
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
Expression exp = parser.parseExpression(securityExpression);
SecurityExpressionRoot context = new CustomMethodSecurityExpressionRoot(authentication);
boolean result = exp.getValue(context, Boolean.class);
logger.info("Check result: " + result);
return result;
}
}
并且在yaml配置文件中你可以配置路径和授权表达式,像这样:
preAuthorize:
whatever:
post: hasRole('MY_ROLE') OR hasAuthority('MY_AUTHORITY')
然后你可以像这样在你的方法中使用它:
@PreAuthorize("@AuthorizationComponent.evaluateExpression('preAuthorize.whatevert.post')")
@RequestMapping(value = "", method = RequestMethod.POST)
public ResponseEntity<Void> addQuestion(@Valid @RequestBody BodyRestDTO bodyRestDTO){
//Code implementation
return new ResponseEntity<Void>(HttpStatus.CREATED);
}