Method Security in GraalVM Native Image

虽然 GraalVM Native Image 中支持 Method Security,但有些用例需要应用程序提供的附加提示。

Using @PreAuthorize and @PostAuthorize Annotations

如果您有 UserDetailsAuthentication 类 自定义实现,则使用 @PreAuthorize@PostAuthorize 注释需要附加提示信息。

我们举一个示例,其中您使用自定义实现 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!";
}

请记住,您需要将 add @EnableMethodSecurity annotation 添加到配置类,以便启用方法安全注释。

如果您使用以上配置 run the native image 应用程序,那么在尝试调用 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

这意味着 isAdmin() 方法无法在 CustomUserDetails 类中找到。这是因为 Spring Security 使用反射来调用 isAdmin() 方法,而 GraalVM 本机图像在默认情况下不支持反射。

要解决这个问题,你需要给 GraalVM Native Image 提供提示以允许对 CustomUserDetails#isAdmin() 方法进行反射。我们可以通过提供一个 custom hint 来做到这一点。在此示例中,我们将使用 {spring-framework-reference-url}core.html#core.aot.hints.register-reflection-for-binding[@RegisterReflectionForBinding 注释]。

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

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

就是这样,现在您可以运行应用程序的本机映像了,并且它应该按预期工作。