【问题标题】:Spring Boot property in @Preauthorize@Preauthorize 中的 Spring Boot 属性
【发布时间】:2016-04-16 02:06:59
【问题描述】:

我正在设置一个 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() 方式访问它,但是我很高兴知道我是否能够直接访问该属性。

【问题讨论】:

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


【解决方案1】:

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

【讨论】:

  • 有道理,但 Spring 允许使用基于属性的注释。它可以使用代理或类似物来实现。看看这个链接。 stackoverflow.com/questions/26451321/… stackoverflow.com/questions/26394778/… 我只是担心@PreAuthorized 注释是否可行。
  • 我想避免在 bean 变量中设置值,但总之会尝试一下。为您的研究工作 +1 ;-)
  • 各位,我们现在快到 2021 年了,有没有可能直接在 PreAuthorize 注释中使用 ${mysecurity.permit} ?感谢您提供任何更新的答案。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    这应该可行:

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

    【讨论】:

    • 该属性正在其他类中被识别(如@ConditionalOnProperty(value = ${mysecurity.permit}")),因此该属性本身没有问题。问题似乎是从@PreAuthorize 访问它。
    猜你喜欢
    • 2013-08-14
    • 2016-10-28
    • 2020-09-24
    • 2021-05-02
    • 2016-12-27
    • 2019-04-13
    • 2016-07-06
    • 2018-01-01
    • 2014-07-25
    相关资源
    最近更新 更多