我正在开发一个Spring服务,它有一个REST控制器和一个Netflix DGS GraphQL组件。REST方法受到Security的保护,每当需要当前用户名时,我就使用@AuthenticationPrincipal注释添加一个方法参数,它允许我访问经过身份验证的用户信息:
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
@RestController
public class ActionController {
@GetMapping("/getActions")
public List<ActionResponse> getActions(@AuthenticationPrincipal UserDetails userDetails) {
return actionService.getActions(userDetails.getUsername());
}
}现在,我希望对通过GraphQL实现的Netflix DGS方法具有相同的功能。但是,当我尝试使用@AuthenticationPrincipal参数(如第一个例子)时,它总是等于null。我找到的解决办法是从SecurityContextHolder手动分配SecurityContextHolder:
import com.netflix.graphql.dgs.DgsComponent;
import com.netflix.graphql.dgs.DgsQuery;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
@DgsComponent
public class ActionDatafetcher {
@DgsQuery
public List<Map<String, Object>> actions(@AuthenticationPrincipal UserDetails userDetails) {
// The following line works well:
// userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = userDetails.getUsername(); // ===> NullPointerException here
return actionService.getActionsMap(username);
}
}如何让@Authentication主体在DgsComponent中工作?
发布于 2022-09-27 20:02:59
即使Security的AuthenticationPrincipalArgumentResolver在应用程序上下文中,默认情况下它也不会被DGS选中。您可以通过实现DGS自己的ArgumentResolver并将其工作委托给Spring的AuthenticationPrincipalArgumentResolver来实现这一点。
所以你所需要做的就是:
Kotlin
@Component
class DgsAuthenticationPrincipalArgumentResolver : ArgumentResolver {
private val delegate = AuthenticationPrincipalArgumentResolver()
override fun supportsParameter(parameter: MethodParameter): Boolean {
return delegate.supportsParameter(parameter)
}
override fun resolveArgument(parameter: MethodParameter, dfe: DataFetchingEnvironment): Any? {
val request = (DgsDataFetchingEnvironment(dfe).getDgsContext().requestData as DgsWebMvcRequestData).webRequest as NativeWebRequest
return delegate.resolveArgument(parameter, null, request, null)
}
}Java
@Component
public class DgsAuthenticationPrincipalArgumentResolver implements ArgumentResolver {
private final AuthenticationPrincipalArgumentResolver delegate = new AuthenticationPrincipalArgumentResolver();
@Nullable
@Override
public Object resolveArgument(@NotNull MethodParameter parameter, @NotNull DataFetchingEnvironment dfe) {
DgsContext context = ((DataFetchingEnvironmentImpl) dfe).getContext();
DgsWebMvcRequestData requestData = (DgsWebMvcRequestData) context.getRequestData();
NativeWebRequest request = requestData == null ? null : (NativeWebRequest) requestData.getWebRequest();
return delegate.resolveArgument(parameter, null, request, null);
}
@Override
public boolean supportsParameter(@NotNull MethodParameter parameter) {
return delegate.supportsParameter(parameter);
}
}在2n和第4个参数上传递nulls是可以的,因为它们在委派的resolveArgument中没有使用,因为您可以检查这里。
https://stackoverflow.com/questions/73055108
复制相似问题