【问题标题】:How to enable @AuthenticationPrincipal argument in a DGS query如何在 DGS 查询中启用 @AuthenticationPrincipal 参数
【发布时间】:2022-09-28 04:02:59
【问题描述】:

我正在开发一个同时具有 REST 控制器和 Netflix DGS GraphQL 组件的 Spring Boot 服务。 REST 方法受 Spring 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 方法具有相同的功能。但是当我尝试使用@AuthenticationPrincipal 参数时(如第一个示例),它总是等于null。我发现的解决方法是从 SecurityContextHolder 手动分配 userDetails:

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

}

如何让 @AuthenticationPrincipal 在 DgsComponent 中工作?

    标签: java spring-boot authentication spring-security netflix-dgs


    【解决方案1】:

    尽管 Spring Security 的 AuthenticationPrincipalArgumentResolver 在应用程序上下文中,但默认情况下 DGS 不会拾取它。您可以通过实现 DGS 自己的 ArgumentResolver 并将其工作委托给 Spring 的 AuthenticationPrincipalArgumentResolver 来实现这一点。

    所以你需要创建的就是这个(我的代码是用 Kotlin 编写的,但我假设任何人都可以轻松地将它转换为 Java):

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

    在第二个和第四个参数上传递nulls 是可以的,因为它们在委派的resolveArgument 中没有使用,您可以检查here

    【讨论】:

      猜你喜欢
      • 2019-02-10
      • 1970-01-01
      • 1970-01-01
      • 2020-11-20
      • 1970-01-01
      • 2021-12-05
      • 2019-07-24
      • 2016-06-17
      • 2018-08-12
      相关资源
      最近更新 更多