@Preauthorize中的Spring Boot属性

时间:2016-01-11 17:00:28

标签: spring spring-security spring-boot spring-el

我正在设置Spring Boot(v1.2.6)Web项目并使用Spring Security(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()方式访问它,但是我很高兴知道我是否能够直接访问该属性。

3 个答案:

答案 0 :(得分:4)

注释中使用的值必须是常量。它们在编译时进行评估,虽然可以保留它们以便在运行时使用,但它们不会被重新评估。因此,您可以使用由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
  }
}

答案 1 :(得分:1)

这可能是评估我想与您共享的表达式的通用方法:

@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);
}

答案 2 :(得分:0)

这应该有效:

@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>