跳到主要内容

GraalVM 原生镜像中的方法安全性

DeepSeek V3 中英对照 Method Security Method Security in GraalVM Native Image

尽管 GraalVM 原生镜像支持 方法安全,但某些用例需要应用程序提供额外的提示。

使用 @PreAuthorize@PostAuthorize 注解

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

让我们以一个例子来说明,假设你有一个自定义的 UserDetails 类实现如下,并且该实现由你的 UserDetailsService 返回:

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
}
java

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

@PreAuthorize("principal?.isAdmin()")
public String hello() {
return "Hello!";
}
java
备注

请记住,你需要在配置类中添加 @EnableMethodSecurity 注解 以启用方法安全注解。

如果你使用上述配置运行应用程序的原生镜像,在尝试调用 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
none

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

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

备注

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

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

就是这样,现在你可以运行应用程序的原生镜像,它应该会按预期工作。