GraalVM 原生镜像中的方法安全

本站(springdoc.cn)中的内容来源于 spring.io ,原始版权归属于 spring.io。由 springdoc.cn 进行翻译,整理。可供个人学习、研究,未经许可,不得进行任何转载、商用或与之相关的行为。 商标声明:Spring 是 Pivotal Software, Inc. 在美国以及其他国家的商标。

尽管 GraalVM Native Image 支持 Method Security,但有一些用例需要应用程序提供额外的 hint。

使用 @PreAuthorize@PostAuthorize 注解

如果你有 UserDetailsAuthentication 类的自定义实现,使用 @PreAuthorize@PostAuthorize 注解需要额外的 hint。

举个例子,你有一个自定义的 UserDetails 类的实现,如下所示,该实现由你的 UserDetailsService 返回:

Custom Implementation of UserDetails
public class CustomUserDetails implements UserDetails {

    private final String username;

    private final String password;

    private final Collection<? extends GrantedAuthority> authorities;

    public boolean isAdmin() {
        return this.authorities.contains(new SimpleGrantedAuthority("ROLE_ADMIN"));
    }

    // constructors, getters and setters
}

而你想在 @PreAuthorize 注解中使用 isAdmin() 方法,如下所示:

Using isAdmin() to secure a method
@PreAuthorize("principal?.isAdmin()")
public String hello() {
    return "Hello!";
}

记住,你需要在你的配置类中 添加 @EnableMethodSecurity 注解,以启用 method security 注解,如下:

如果你用上述配置 运行 你的应用程序的原生镜像,在试图调用 hello() 方法时,你会得到一个类似于以下的错误:

failed: java.lang.IllegalArgumentException: Failed to evaluate expression 'principal?.isAdmin()' with root cause
org.springframework.expression.spel.SpelEvaluationException: EL1004E: Method call: Method isAdmin() cannot be found on type com.mypackage.CustomUserDetails

这意味着在 CustomUserDetails 类中找不到 isAdmin() 方法。这是因为Spring Security 使用反射来调用 isAdmin() 方法,而 GraalVM Native Image 默认不支持反射。

为了解决这个问题,你需要给 GraalVM Native Image 提供 hint,允许对 CustomUserDetails#isAdmin() 方法进行反射。我们可以通过提供一个 自定义 hint 来做到这一点。在这个例子中,我们将使用 @RegisterReflectionForBinding 注解

你可能需要在你的 @PreAuthorize@PostAuthorize 注解中注册所有你想使用的类。

Using @RegisterReflectionForBinding
@Configuration
@RegisterReflectionForBinding(CustomUserDetails.class)
public class MyConfiguration {
    //...
}

就这样,现在你可以运行你的应用程序的原生镜像了,它应该能如期工作。