我们将 spqr graphQl 与 Spring 一起使用。它工作得很好并且简化了很多,谢谢!现在我们使用 ResolverInterceptor 进行授权:从 DefaultGlobalContext 读取 JWT-Token 并进行验证。我们还能够从这个令牌中确定当前的用户名。所以现在我的问题是:我可以将此用户名存储在 spring bean 中吗?spring bean 和上下文之间有什么联系吗?我们目前所做的是将 DefaultGlobalContext 作为@GraphQLRootContext 注入到我们@GraphQLApi 的每个方法中,并以这种方式获取用户。如果我们可以只读取一次,将其存储在某个地方并可以在 Spring 托管服务中访问,那就更好了。有谁知道这是怎么做到的吗?提前致谢, 马蒂亚斯
问问题
1023 次
1 回答
3
你可以做几件事。
1. 定制ArgumentInjector
最简单的方法(也是我推荐的方法)是连接自定义ArgumentInjector
. 您可以使其对某些注释或仅按类型做出反应。例如
@Query
public Book book(String id, @LoggedIn User user) {...}
还有一个像这样的注射器:
public UserInjector implement ArgumentInjector {
@Override
public Object getArgumentValue(ArgumentInjectorParams params) {
ResolutionEnvironment env = params.getResolutionEnvironment();
return extractUserFromRootContext(env.rootContext);
}
@Override
public boolean supports(AnnotatedType type, Parameter parameter) {
//You can also check type.getType().equals(User.class), but IMHO explicit is always better
return parameter != null && parameter.isAnnotationPresent(LoggedIn.class);
}
}
2.自定义GraphQLExecutor
和请求范围的bean
另一种方法是让一个@RequestScoped
bean 注入GraphQLExecutor
到你的类和你的@GraphQLApi
类中。
@Component
//implements GraphQLServletExecutor
public class CustomGraphQLExecutor extends DefaultGraphQLExecutor {
//This is @RequestScoped
private UserHolder userHolder;
@Autowired
public CustomGraphQLExecutor(
ServletContextFactory contextFactory,
Optional<DataLoaderRegistryFactory> registryFactory,
UserHolder userHolder) {
super(contextFactory, registryFactory.orElse(null));
this.userHolder = userHolder;
}
@Override
public Map<String, Object> execute(GraphQL graphQL, GraphQLRequest graphQLRequest, NativeWebRequest nativeRequest) {
userHolder.setUser(getUserFromTheRequest(nativeRequest));
return super.execute(graphQL, graphQLRequest, nativeRequest);
}
}
@Service
@GraphQLApi
public class BookService {
@Autowired
private UserHolder userHolder; //@RequestScoped
@Query
public Book book(String id) {
//Access userHolder as needed
...
}
}
我不喜欢这种方法,因为它对ThreadLocal
. 如果在任何时候您开始使解析器异步(这很可能使用 graphql-java),您将需要特别包装的线程池,否则这些东西根本无法工作。(另外,如果你曾经求助于 WebFlux,它可能根本不起作用,因为 graphql-java 不支持 Reactor 并且无法传播上下文)。
3. 使用 Spring Security
由于您所做的只是基本的 Spring Security 内容,因此只需使用它为您提供的功能。它与请求范围的 bean 方法具有相同的问题,但您至少不必自己做任何事情。Spring 已经让您SecurityContext
可以从任何地方访问。而且如果自定义了控制器类,也可以直接将Principal
/注入Authentication
到控制器方法中。
于 2019-10-23T09:23:26.157 回答