认证和中间件
控制具有权限的人去访问数据接口,需要借助于express的中间件来实现
中间件的本质实际上是一个
function,它在接口执行之前首先拦截请求,然后决定是往下走还是返回错误消息
const express = require('express');
const {
buildSchema
} = require('graphql');
const {
graphqlHTTP
} = require('express-graphql');
// 定义schema,查询和类型
const schema = buildSchema(`
input AccountInput {
name: String
age: Int
gender: String
department: String
}
type Account {
name: String
age: Int
gender: String
department: String
}
type Mutation {
createAccount(input: AccountInput): Account
updateAccount(id: ID, input: AccountInput): Account
}
type Query {
accounts: [Account]
}
`)
// 定义一个假的数据库
const fakeDb = {};
// 定义查询对应的解析器
const root = {
accounts(){
var arr = [];
for(const i in fakeDb){
arr.push(fakeDb[i]);
}
return arr;
},
// 这里的input相当于拿到的所有字段
createAccount({ input }){
// 相当于数据库的保存
fakeDb[input.name] = input;
// 返回保存的结果
return fakeDb[input.name];
},
updateAccount({ id, input }){
// 相当于数据库的更新
// 从fakeDb中拿到需要的fakeDb[id],拿到之后将input新的属性覆盖到它身上
const updatedAccount = Object.assign({}, fakeDb[id], input);
// 将更新保存到数据库
fakeDb[id] = updatedAccount;
// 返回更新的结果
return updatedAccount;
}
}
const app = express();
// 中间件
const middleware = (req, res, next) => {
// 判断访问地址中包含/graphql这个字样并且cookie中没有auth的时候
if(req.url.indexOf('/graphql') !== -1 && req.headers.cookie.indexOf('auth') === -1){
res.send(JSON.stringify({
error: "当前没有权限访问该接口"
}));
return;
}
next();
};
// 中间件的注册
app.use(middleware);
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true
}));
app.listen(9000, () => {
console.log("http://localhost:9000/graphql")
});
middleware
中先检测访问的地址是不是/graphql
,如果是这个地址,接着看一下cookie
中是否包含auth
这个字样,如果没有包含则抛出错误提示,否则就next()
正常往下走


上面没有权限访问的原因是因为cookie中没有auth
这个字段,可以在application中加一个之后刷新访问就可以
上面是通过一个小例子来说明中间件对权限验证,在真正的项目中是需要跟服务器端进行配合的:服务器端生成一个token,将token交给前端,前端在访问接口时将token带回来,拿到token之后对它进行一个检查
构造类型
之前的schema是通过buildSchema👇
const schema = buildSchema(`
// 定义类型
type Account {
name: String
age: Int
gender: String
department: String
}
// 定义Query
type Query {
accounts: [Account]
}
`)
现在要说的是将类型的定义变成构造函数的形式进行,之前一步可以完成的现在需要三步,先定义type
,然后定义Query
,最后将Query
转成schema
👇
- 使用GeaphQLObjectType定义type(类型)
var AccountType = new graphql.GraphQLObjectType({
name: 'Account',
fields: {
name: { type: graphql.GraphQLString },
age: { type: graphql.GraphQLInt },
gender: { type: graphql.GraphQLString },
department: { type: graphql.GraphQLString }
}
});
- 使用GeaphQLObjectType定义query(查询)
var queryType = new graphql.GraphQLObjectType({
name: 'Query',
fields: {
account: {
type: AccountType,
args: {
username: {
type: graphql.GraphQLString
},
},
resolver: function (_, { username }) {
const name = username;
const age = 18;
const gender = 'female';
const department = 'xian';
return {
name,
age,
gender,
department
}
}
}
}
});
- 创建schema
var schema = new graphql.GraphQLSchema({ query: queryType });
const express = require('express');
const { graphql } = require('graphql');
const { buildSchema } = require('graphql');
const { graphqlHTTP } = require('express-graphql');
var AccountType = new graphql.GraphQLObjectType({
name: 'Account',
fields: {
name: { type: graphql.GraphQLString },
age: { type: graphql.GraphQLInt },
gender: { type: graphql.GraphQLString },
department: { type: graphql.GraphQLString }
}
});
var queryType = new graphql.GraphQLObjectType({
name: 'Query',
fields: {
account: {
type: AccountType,
args: {
username: {
type: graphql.GraphQLString
},
},
resolver: function (_, { username }) {
const name = username;
const age = 18;
const gender = 'female';
const department = 'xian';
return {
name,
age,
gender,
department
}
}
}
}
});
var schema = new graphql.GraphQLSchema({ query: queryType });
// 定义一个假的数据库
const fakeDb = {};
// 定义查询对应的解析器
const root = {
accounts() {
var arr = [];
for (const i in fakeDb) {
arr.push(fakeDb[i]);
}
return arr;
},
// 这里的input相当于拿到的所有字段
createAccount({ input }) {
// 相当于数据库的保存
fakeDb[input.name] = input;
// 返回保存的结果
return fakeDb[input.name];
},
updateAccount({ id, input }) {
// 相当于数据库的更新
// 从fakeDb中拿到需要的fakeDb[id],拿到之后将input新的属性覆盖到它身上
const updatedAccount = Object.assign({}, fakeDb[id], input);
// 将更新保存到数据库
fakeDb[id] = updatedAccount;
// 返回更新的结果
return updatedAccount;
}
}
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true
}));
app.listen(9000, () => {
console.log("http://localhost:9000/graphql")
});
这样的变化带来的好处是比较好维护,哪块出错了之后就可以精确到出错的那个type