我需要在apollo订书机服务器中添加一个授权层,但是找不到任何解决方案。
架构:-有一个中央apollo Graphql网关服务器(缝合服务器),该服务器与其他微服务进行通信并将其架构缝合在一起。我希望将授权和身份验证层从每个微服务(以不同的语言编写)移动到网关服务器,这样任何未经授权的请求都将无法通过网关服务器,并且我们不必以每种语言编写授权层。>
因此,为了使授权有效,我们决定使用@auth(role: ADMIN)
之类的指令,但是问题在于它不适用于缝合的模式。
微服务A(java)
schema.graqhql
directive @auth(requires: String) on FIELD | FIELD_DEFINITION | OBJECT | QUERY
type Campaign {
name: String
status: Status
}
// I have added a dummy auth directive resolver in java microservice such that it doesn't fail schema validation at server startup.
type Query {
campaigns : [Camapign] @auth(role: ADMIN)
}
Apollo网关服务器
AuthDirective.js
// @flow
import {SchemaDirectiveVisitor} from "apollo-server";
class AuthDirective extends SchemaDirectiveVisitor {
visitObject(object) {
console.log("in visitObject");
this.ensureFieldsWrapped(object);
}
visitFieldDefinition(field) {
const {resolve} = field;
console.log("in visitFieldDefinition");
field.resolve = async function (...args) {
console.log("in auth resolver");
const context = args[2];
const requiredRole = "ADMIN";
const user = await getUser(context.headers.authToken);
if (!user.hasRole(requiredRole)) {
throw new Error("not authorized");
}
return resolve.apply(this, args);
};
}
ensureFieldsWrapped(objectType) {
const fields = objectType.getFields();
Object.keys(fields).forEach(fieldName => {
const field = fields[fieldName];
const {resolve} = field;
field.resolve = async function (...args) {
console.log("in auth resolver");
const context = args[2];
const requiredRole = "ADMIN";
const user = await getUser(context.headers.authToken);
if (!user.hasRole(requiredRole)) {
throw new Error("not authorized");
}
return resolve.apply(this, args);
};
});
}
}
export default AuthDirective;
// language=GraphQL
// will this directive override the directive in Microservice A ?
const RootQuery= `
directive @auth(
requires: String
) on FIELD | FIELD_DEFINITION | OBJECT | QUERY
`;
async function getMergedSchema() {
const remoteSchema = await makeMergedRemoteSchema(); // introspects microservice schemas using makeRemoteExecutableSchema
const schema = makeExecutableSchema({
typeDefs: RootQuery,
schemaDirectives: {
auth: AuthDirective
}
});
return [
...remoteSchema,
schema
];
}
//app.js
const schemas = await getMergedSchema();
const mergedSchema = mergeSchemas({
schemas,
resolvers: resolvers,
mergeDirectives: true
}});
const server = new ApolloServer({
schema: mergedSchema,
debug: true,
introspection: true,
tracing: true,
engine: {
apiKey: config.get("engine.apiKey"),
schemaTag: process.env.NODE_CONFIG_ENV,
generateClientInfo: ({request}) => {
const headers = request.http && request.http.headers;
if (headers) {
return {
clientName: headers.get("X-clientId"),
clientVersion: headers.get("X-AppVersion"),
};
} else {
return {
clientName: "Unknown",
clientVersion: "Unknown"
};
}
}
},
cacheControl: true,
playground: {
settings: {
"editor.theme": "dark",
},
},
persistedQueries: {
cache: new MemcachedCache(
['memcached-server'],
{retries: 10, retry: 10000, ttl: 10000},
),
},
subscriptions: {
path: "/sub"
},
context: ({req}) => ({
request: req
})
});
server.applyMiddleware({
app,
gui: true,
bodyParserConfig: {limit: "50mb"},
cors: {
origin: "*"
},
onHealthCheck: () => new Promise((resolve) => {
//database check or other asynchronous action
resolve();
})
});
const httpServer = http.createServer(app);
server.installSubscriptionHandlers(httpServer);
httpServer.listen({
port: ((port: any): number)
}, () => {
Logger.info(`? Server ready at http://localhost:${port}${server.graphqlPath}`);
Logger.info(`Try your health check at: http://localhost:${port}/.well-known/apollo/server-health`);
}
)
查询到Apollo服务器
{
campaigns {
name
}
}
我希望在打此查询时调用订书机中的@auth directive
,以便我可以控制它并检查传入请求是否得到授权。如果不是,则抛出UNAUTHORIZED错误,并且不会将请求转发给微服务。
但是它会在微服务A中调用auth指令:(
有什么方法可以实现这一目标,或者如果您有更好的解决方案或体系结构,请告诉我。我被困住需要帮助。
我正在使用以下软件包
{
...,
"dependencies": {
"@types/graphql": "14.2.0",
"apollo-engine": "1.1.2",
"apollo-fetch": "0.7.0",
"apollo-link-context": "1.0.17",
"apollo-link-http": "1.5.14",
"apollo-server": "2.6.0-alpha.0",
"apollo-server-cache-memcached": "0.4.0",
"apollo-server-express": "2.6.0-alpha.0",
"apollo-server-memcached": "0.1.0-rc.10",
"express": "4.16.4",
"graphql": "14.3.1",
"graphql-resolve-batch": "1.0.2",
"graphql-subscriptions": "1.1.0",
"graphql-tag": "2.10.1",
"graphql-tools": "5.0.0-rc.1",
"node-fetch": "2.5.0",
"request": "2.88.0",
"subscriptions-transport-ws": "0.9.16",
"ws": "5.2.1",
...
}
}