巴拉巴

 找回密码
 立即注册

站内搜索

搜索
热搜: 活动 交友 discuz
查看: 6|回复: 0

GraphQL请求上下文

[复制链接]

3

主题

6

帖子

13

积分

新手上路

Rank: 1

积分
13
发表于 2023-1-23 12:03:24 | 显示全部楼层 |阅读模式
学无止境,无止境学。坚持每天学点编程知识,坚持每天写点小文章,坚持每天进步一点点。大家好,我是张大鹏,喜欢学习和分享,希望能够通过此公众号,将自己学到的东西分享给大家,和大家一起交流,一起成长,一起进步。
乾坤未定,你我皆是黑马。大鹏一日同风起,扶摇直上九万里。宝剑锋从磨砺出,梅花香自苦寒来。不积跬步,无以至千里,不积小流无以成江海。
如果有多余的时间,就坚持学习吧,小时候学习改变命运,长大了学习丰富内涵,老了学习带来宁静。活到老,学到老,我能行!
《JavaScript全栈班》收费说明:
时长:50节课
价格:9999元
内容:
NodeJS开发后端API
React开发H5端
Electron开发桌面端软件
ReactNative开发Android和iOS跨端APP
本篇文章是《JavaScript全栈班》的第14篇文章,前面还有:
《搭建JavaScript全栈开发环境》
《NodeJS和GraphQL构建社交笔记API》
《使用Express开发Web应用》
《第一个GraphQL API》
《基于GraphQL的笔记增删改查API》
《NodeJS整合MongoDB》
《GraphQL整合MongoDB》
《GraphQL模块化开发》
《GraphQL实现增删改查API》
《GraphQL自定义日期时间类型》
《NodeJS密码加密和校验》
《NodeJS实现JWT Token》
《GraphQL整合JWT实现用户注册登录》
请求上下文在很多框架中都有使用,核心用法就是用于存储通用数据,比如咱们之前写好的JWT Token,该token从前端传递到后端以后,如果在每个方法中都重新获取,会有很多耦合的代码,所以我们可以将token解析的代码写在请求上下文中,实现代码的简化。
第一步:使用登录接口,获取JWT Token
mutation{
login(
username: "zhangdapeng",
password: "zhangdapeng521",
)
}
第二步:在GraphQL API中,添加HTTP Headers,将token添加到请求头中
{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYzYzdiOGMzN2Q1M2RlMzkxYzgyNTBkMCIsInVzZXJuYW1lIjoiemhhbmdkYXBlbmciLCJpYXQiOjE2NzQyMTQ1NzAsImV4cCI6MTY3NDIyNTM3MH0.Rv70jyV92pzoZO1J-iPnmQPx74esQURFqKfzRf0o71o"
}
第三步:数据经过请求上下文,被解析,然后返回
context: async ( { req } ) =>
{
// 获取token
const token = req.headers.authorization
console.log( "请求头中的token", token );
const user = await parseToken( token );
console.log( "222 解析token", user )
// 返回
return { user }
}
第四步:在需要设置权限的接口中解析并查看token的解析结果
newNote: async ( parent, args, { user } ) =>
{
// 从上下文中解析数据
console.log( "请求上下文获取", user );
// 新增
let noteValue = {
content: args.content,
author: "张大鹏",
addTime: new Date,
updateTime: new Date,
}
await add( [ noteValue ] )
// 返回数据,新增会直接修改该对象
return noteValue
},
PORT=4001
DB_URL=mongodb://localhost:27017
DB_USERNAME=zhangdapeng
DB_PASSWORD=zhangdapeng520
DB_DATABASE=notes
JWT_SECRET="zhangdapeng520"
JWT_EXPIRES=10800
require( 'dotenv' ).config;
const { MongoClient, ObjectId } = require( 'mongodb' );
// 从环境变量读取相关DB信息
const URL = process.env.DB_URL;
const USERNAME = process.env.DB_USERNAME;
const PASSWORD = process.env.DB_PASSWORD;
const DATABASE = process.env.DB_DATABASE;
// 创建客户端
const client = new MongoClient( URL, options = {
auth: {
username: USERNAME,
password: PASSWORD,
}
} );
// 添加数据
async function add ( data )
{
// 等待连接
await client.connect;
// 获取集合
const collection = client.db( DATABASE ).collection( 'documents' );
// 添加数据
// data = [ { a: 1 }, { a: 2 }, { a: 3 } ]
const result = await collection.insertMany( data );
await client.close;
return result
}
// 查询数据
async function find ( data )
{
// 等待连接
// 获取集合
// 查询数据
// data = {}
const result = await collection.find( data ).toArray;
return result
}
async function findOne ( data )
{
// 等待连接
// 获取集合
// 查询数据
// data = {}
const result = await collection.findOne( data );
return result
}
async function updateOne ( query, data )
{
// 等待连接
// 获取集合
// 修改数据
const result = await collection.updateOne( query, { $set: data } );
return result
}
async function deleteOne ( data )
{
// 等待连接
// 获取集合
// 删除数据
// data = {}
const result = await collection.deleteOne( data )
return result
}
// 导出集合操作对象
module.exports = {
ObjectId,
add,
find,
findOne,
updateOne,
deleteOne,
};
const bcrypt = require( 'bcrypt' );
// 密码加密
const hashPassword = async ( passwordText, saltRounds = 10 ) =>
{
return await bcrypt.hash( passwordText, saltRounds )
}
// 密码校验
const checkPassword = async ( passwordText, hashPassword ) =>
{
return bcrypt.compare( passwordText, hashPassword )
}
module.exports = {
hashPassword,
checkPassword,
}
const jwt = require( 'jsonwebtoken' );
const JWT_SECRET = process.env.JWT_SECRET
const JWT_EXPIRES = parseInt( process.env.JWT_EXPIRES )
// 生成token
const getToken = async ( data ) =>
{
return jwt.sign( data, JWT_SECRET, { expiresIn: JWT_EXPIRES } );
}
// 解析token
const parseToken = async ( token ) =>
{
return jwt.verify( token, JWT_SECRET );
}
module.exports = {
getToken,
parseToken,
}
const { gql } = require( 'apollo-server-express' );
// 使用 GraphQL 模式语言编制一个模式
const typeDefs = gql`
scalar DateTime
type Note {
_id: ID!
content: String
author: String
addTime: DateTime
updateTime: DateTime
}
type User {
_id: ID!
username: String
avatar: String
notes: [Note]
addTime: DateTime
updateTime: DateTime
}
type Query {
notes: [Note]!
note(id: ID): Note!
}
type Mutation {
newNote(content: String): Note!
updateNote(id: ID!, content: String): Note!
deleteNote(id: ID!): Boolean!
register(username: String!, password: String!, rePassword: String!): String!
updatePassword(username: String!, oldPassword: String!, password: String!, rePassword: String!): String!
login(username: String!, password: String!): String!
}
`;
module.exports = typeDefs
const { GraphQLDateTime } = require( 'graphql-iso-date' )
const { ObjectId, add, find, findOne, deleteOne, updateOne } = require( './db' )
const { hashPassword, checkPassword } = require( './password' )
const { getToken, parseToken } = require( './jwt' )
// 为模式字段添加解析函数
const resolvers = {
Query: {
notes: async =>
{
return await find( {} )
},
note: async ( parent, args ) =>
{
return await findOne( { "_id": ObjectId( args.id ) } )
}
},
Mutation: {
newNote: async ( parent, args, { user } ) =>
{
// 从上下文中解析数据
console.log( "请求上下文获取", user );
// 新增
let noteValue = {
content: args.content,
author: "张大鹏",
addTime: new Date,
updateTime: new Date,
}
await add( [ noteValue ] )
// 返回数据,新增会直接修改该对象
return noteValue
},
updateNote: async ( parent, args ) =>
{
// 查询
const query = {
"_id": ObjectId( args.id ),
}
// 修改内容
const data = {
}
await updateOne( query, data )
// 返回数据
},
deleteNote: async ( parent, args ) =>
{
await deleteOne( { "_id": ObjectId( args.id ) } )
// 返回
return true
},
register: async ( parent, args ) =>
{
// 校验密码是否正确
if ( !args.password || !args.rePassword )
{
return "密码或确认密码不能为空"
}
if ( args.password !== args.rePassword )
{
return "两次密码不一致"
}
// 新增
let user = {
username: args.username,
password: await hashPassword( args.password ),
addTime: new Date,
}
await add( [ user ] )
return "success"
},
login: async ( parent, { username, password } ) =>
{
if ( !username || !password )
{
return "用户名或密码不能为空"
}
// 查找用户
const user = await findOne( { username } )
if ( !user )
{
return "用户不存在"
}
// 校验密码
if ( !await checkPassword( password, user.password ) )
{
return "用户名或密码不正确"
}
// 生成JWT Token
const data = {
id: user._id,
username: user.username,
}
console.log( "用户token", data )
const token = await getToken( data );
// 返回token
return token
},
updatePassword: async ( parent, { username, oldPassword, password, rePassword } ) =>
{
if ( !username )
{
return "用户名不能为空"
}
if ( !oldPassword )
{
return "旧密码不能为空"
}
if ( !password )
{
return "密码不能为空"
}
if ( !rePassword )
{
return "确认密码不能为空"
}
if ( password !== rePassword )
{
return "两次密码不一致"
}
// 查找用户
if ( !user )
{
return "用户不存在"
}
// 校验密码
if ( !await checkPassword( oldPassword, user.password ) )
{
return "旧密码不正确"
}
// 修改
const query = {
"_id": user._id,
}
const data = {
password: await hashPassword( password ),
}
// 返回
return "success"
}
},
DateTime: GraphQLDateTime,
};
module.exports = resolvers
require( 'dotenv' ).config; // 读取.env作为环境变量
const express = require( 'express' );
const { ApolloServer } = require( 'apollo-server-express' );
const { parseToken } = require( './jwt' )
const typeDefs = require( "./schema" )
const resolvers = require( "./resolvers" )
// 读取端口
const PORT = process.env.PORT || 4000;
const app = express;
// 设置Apollo Server
const server = new ApolloServer( {
typeDefs,
resolvers,
context: async ( { req } ) =>
{
// 获取token
const token = req.headers.authorization
console.log( "请求头中的token", token );
const user = await parseToken( token );
console.log( "222 解析token", user )
// 返回
return { user }
}
} );
// 应用 Apollo GraphQL 中间件,把路径设为 /api
server.applyMiddleware( { app, path: '/api' } );
// 监听端口
app.listen( PORT, =>
console.log( `启动服务成功:http://localhost:${ PORT }${ server.graphqlPath }` )
);
npm run dev
mutation{
login(
username: "zhangdapeng",
)
}
修改请求头:
{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYzYzdiOGMzN2Q1M2RlMzkxYzgyNTBkMCIsInVzZXJuYW1lIjoiemhhbmdkYXBlbmciLCJpYXQiOjE2NzQyMTQ1NzAsImV4cCI6MTY3NDIyNTM3MH0.Rv70jyV92pzoZO1J-iPnmQPx74esQURFqKfzRf0o71o"
}
通过以下参数发送请求:
mutation{
newNote(content: "今天学习GrapQL 5"){
_id
author
content
addTime
updateTime
}
}

来源:http://www.yidianzixun.com/article/0loXDQ3g
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

  • 返回顶部