GraphQl+ jwt auth+ Axios IS不起作用并抛出错误:错误:访问被拒绝!您需要被授权执行此操作

发布于 2025-02-07 21:03:42 字数 10233 浏览 1 评论 0原文

我对GraphQL有一个后端,并且使用JWT Auth对其进行保护。 当我使用失眠发送GraphQL请求时,它可以正常工作! 但是,当我使用Axios发送时,它不起作用。我正在使用React本机

考虑考虑:

  • JWT未过期,因为我可以复制/粘贴它并使用失眠症,
  • 我可以使用其他方法进行相同的请求,例如:失眠,使用其他脚本
  • API_URI直接调用: http:// localhost:3000/development/,
  • Axios版本(APP):0.27.2
  • GraphQl版本(APP):15.5.1
  • GraphQl-TAG版本(APP):2.12.5
/* eslint-disable no-console */
import axios, { AxiosRequestConfig } from 'axios';
import config from '../../config';
import store from '../stores';

const api = axios.create({
  baseURL: config.API_URI,
});

api.interceptors.request.use((config: AxiosRequestConfig) => {
  const { token, pushNotificationToken } = store.getState().user;
  config.headers.Authorization = `Bearer ${token}`;
  config.headers.pushnotificationtoken = pushNotificationToken || '';

  return config;
});

api.interceptors.request.use(request => {
  console.log(
    '\n======================= STARTING REQUEST ===========================\n',
  );
  console.log(JSON.stringify(request, null, 2));
  console.log(
    '\n======================= ENDING REQUEST ===========================\n',
  );
  return request;
});

api.interceptors.response.use(response => {
  console.log(
    '\n======================= STARTING RESPONSE ===========================\n',
  );
  console.log(JSON.stringify(response, null, 2));
  console.log(
    '\n======================= ENDING RESPONSE ===========================\n',
  );

  return response;
});

export async function apiRequest<ResponseType>(
  body: any,
): Promise<ResponseType> {
  const response = await api.post('graphql', body);

  const { data } = response;

  if (data.errors && data.errors.length > 0) {
    throw new Error(data.errors[0].message || 'Ops! An error has occurred.');
  }

  return data.data;
}

export default api;


使用AXIOS来自后端的响应:使用Axios:使用

{
    "data": {
        "errors": [{
            "message": "Access Denied",
            "locations": [{
                "line": 2,
                "column": 3
            }],
            "path": [
                "getAllOrders"
            ],
            "extensions": {
                "code": "INTERNAL_SERVER_ERROR",
                "exception": {
                    "stacktrace": [
                        "Error: Access denied! You need to be authorized to perform this action!",
                        "    at /home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/helpers/auth-middleware.js:13:1",
                        "    at dispatchHandler (/home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/resolvers/helpers.js:82:1)"
                    ]
                }
            }
        }],
        "data": null
    },
    "status": 200,
    "headers": {
        "access-control-expose-headers": "WWW-Authenticate,Server-Authorization",
        "connection": "keep-alive",
        "vary": "origin",
        "access-control-allow-credentials": "true",
        "content-length": "601",
        "date": "Tue, 14 Jun 2022 15:32:37 GMT",
        "content-type": "application/json; charset=utf-8",
        "cache-control": "no-cache",
        "keep-alive": "timeout=5"
    },
    "config": {
        "transitional": {
            "silentJSONParsing": true,
            "forcedJSONParsing": true,
            "clarifyTimeoutError": false
        },
        "transformRequest": [
            null
        ],
        "transformResponse": [
            null
        ],
        "timeout": 0,
        "xsrfCookieName": "XSRF-TOKEN",
        "xsrfHeaderName": "X-XSRF-TOKEN",
        "maxContentLength": -1,
        "maxBodyLength": -1,
        "env": {
            "FormData": null
        },
        "headers": {
            "Accept": "application/json, text/plain, */*",
            "Content-Type": "application/json",
            "Authorization": "Bearer + MY JWT TOKEN GOES HERE",
            "pushnotificationtoken": ""
        },
        "baseURL": "http://10.0.2.2:3000/development/",
        "method": "post",
        "url": "graphql",
        "data": "{\"query\":\"query getAllOrders {\\n  getAllOrders {\\n    id\\n    status\\n    table\\n    items {\\n      id\\n      description\\n      quantity\\n      priceCents\\n    }\\n    totalOrderPriceCents\\n    createdAt\\n  }\\n}\\n\"}"
    },
    "request": {
        "UNSENT": 0,
        "OPENED": 1,
        "HEADERS_RECEIVED": 2,
        "LOADING": 3,
        "DONE": 4,
        "readyState": 4,
        "status": 200,
        "timeout": 0,
        "withCredentials": true,
        "upload": {},
        "_aborted": false,
        "_hasError": false,
        "_method": "POST",
        "_perfKey": "network_XMLHttpRequest_http://10.0.2.2:3000/development/graphql",
        "_response": "{\"errors\":[{\"message\":\"Acesso não autorizado\",\"locations\":[{\"line\":2,\"column\":3}],\"path\":[\"getAllOrders\"],\"extensions\":{\"code\":\"INTERNAL_SERVER_ERROR\",\"exception\":{\"stacktrace\":[\"Error: Access denied! You need to be authorized to perform this action!\",\"    at /home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/helpers/auth-middleware.js:13:1\",\"    at dispatchHandler (/home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/resolvers/helpers.js:82:1)\"]}}}],\"data\":null}\n",
        "_url": "http://10.0.2.2:3000/development/graphql",
        "_timedOut": false,
        "_trackingName": "unknown",
        "_incrementalEvents": false,
        "responseHeaders": {
            "access-control-expose-headers": "WWW-Authenticate,Server-Authorization",
            "Connection": "keep-alive",
            "vary": "origin",
            "access-control-allow-credentials": "true",
            "content-length": "601",
            "Date": "Tue, 14 Jun 2022 15:32:37 GMT",
            "content-type": "application/json; charset=utf-8",
            "cache-control": "no-cache",
            "Keep-Alive": "timeout=5"
        },
        "_requestId": null,
        "_headers": {
            "accept": "application/json, text/plain, */*",
            "content-type": "application/json",
            "authorization": "Bearer + jwt goes here",
            "pushnotificationtoken": ""
        },
        "_responseType": "",
        "_sent": true,
        "_lowerCaseResponseHeaders": {
            "access-control-expose-headers": "WWW-Authenticate,Server-Authorization",
            "connection": "keep-alive",
            "vary": "origin",
            "access-control-allow-credentials": "true",
            "content-length": "601",
            "date": "Tue, 14 Jun 2022 15:32:37 GMT",
            "content-type": "application/json; charset=utf-8",
            "cache-control": "no-cache",
            "keep-alive": "timeout=5"
        },
        "_subscriptions": [],
        "responseURL": "http://10.0.2.2:3000/development/graphql"
    }
}

相同的请求使用相同的请求失眠:

“

失眠时间表:

“失眠时间表”

失眠标题

console.log(wendesp.request):



{
  "UNSENT": 0,
  "OPENED": 1,
  "HEADERS_RECEIVED": 2,
  "LOADING": 3,
  "DONE": 4,
  "readyState": 4,
  "status": 200,
  "timeout": 0,
  "withCredentials": true,
  "upload": {},
  "_aborted": false,
  "_hasError": false,
  "_method": "POST",
  "_perfKey": "network_XMLHttpRequest_http://10.0.2.2:3000/development/graphql",
  "_response": "{\"errors\":[{\"message\":\"Acesso não autorizado\",\"locations\":[{\"line\":2,\"column\":3}],\"path\":[\"getAllOrders\"],\"extensions\":{\"code\":\"INTERNAL_SERVER_ERROR\",\"exception\":{\"stacktrace\":[\"Error: Access denied! You need to be authorized to perform this action!\",\"    at /home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/helpers/auth-middleware.js:13:1\",\"    at dispatchHandler (/home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/resolvers/helpers.js:82:1)\"]}}}],\"data\":null}\n",
  "_url": "http://10.0.2.2:3000/development/graphql",
  "_timedOut": false,
  "_trackingName": "unknown",
  "_incrementalEvents": false,
  "responseHeaders": {
    "access-control-expose-headers": "WWW-Authenticate,Server-Authorization",
    "Connection": "keep-alive",
    "vary": "origin",
    "access-control-allow-credentials": "true",
    "content-length": "601",
    "Date": "Tue, 14 Jun 2022 17:42:39 GMT",
    "content-type": "application/json; charset=utf-8",
    "cache-control": "no-cache",
    "Keep-Alive": "timeout=5"
  },
  "_requestId": null,
  "_headers": {
    "accept": "application/json, text/plain, */*",
    "content-type": "application/json",
    "authorization": "Bearer eyJ........",
    "pushnotificationtoken": ""
  },
  "_responseType": "",
  "_sent": true,
  "_lowerCaseResponseHeaders": {
    "access-control-expose-headers": "WWW-Authenticate,Server-Authorization",
    "connection": "keep-alive",
    "vary": "origin",
    "access-control-allow-credentials": "true",
    "content-length": "601",
    "date": "Tue, 14 Jun 2022 17:42:39 GMT",
    "content-type": "application/json; charset=utf-8",
    "cache-control": "no-cache",
    "keep-alive": "timeout=5"
  },
  "_subscriptions": [],
  "responseURL": "http://10.0.2.2:3000/development/graphql"
}

I Have a backend with GraphQL and I use JWT Auth to protect it.
When I sent my GraphQL request using Insomnia, it works properly!
However when I sent using Axios it doesn't work. I'm Using React Native

Some points to consider:

  • Jwt isn't expired, because I can copy/paste it and use using Insomnia
  • I can do the same request using other methods, for example: Insomnia, direct call using other scripts
  • API_URI: http://localhost:3000/development/,
  • Axios Version (app): 0.27.2
  • graphql version (app): 15.5.1
  • graphql-tag version (app): 2.12.5
/* eslint-disable no-console */
import axios, { AxiosRequestConfig } from 'axios';
import config from '../../config';
import store from '../stores';

const api = axios.create({
  baseURL: config.API_URI,
});

api.interceptors.request.use((config: AxiosRequestConfig) => {
  const { token, pushNotificationToken } = store.getState().user;
  config.headers.Authorization = `Bearer ${token}`;
  config.headers.pushnotificationtoken = pushNotificationToken || '';

  return config;
});

api.interceptors.request.use(request => {
  console.log(
    '\n======================= STARTING REQUEST ===========================\n',
  );
  console.log(JSON.stringify(request, null, 2));
  console.log(
    '\n======================= ENDING REQUEST ===========================\n',
  );
  return request;
});

api.interceptors.response.use(response => {
  console.log(
    '\n======================= STARTING RESPONSE ===========================\n',
  );
  console.log(JSON.stringify(response, null, 2));
  console.log(
    '\n======================= ENDING RESPONSE ===========================\n',
  );

  return response;
});

export async function apiRequest<ResponseType>(
  body: any,
): Promise<ResponseType> {
  const response = await api.post('graphql', body);

  const { data } = response;

  if (data.errors && data.errors.length > 0) {
    throw new Error(data.errors[0].message || 'Ops! An error has occurred.');
  }

  return data.data;
}

export default api;


Response from backend Using Axios:

{
    "data": {
        "errors": [{
            "message": "Access Denied",
            "locations": [{
                "line": 2,
                "column": 3
            }],
            "path": [
                "getAllOrders"
            ],
            "extensions": {
                "code": "INTERNAL_SERVER_ERROR",
                "exception": {
                    "stacktrace": [
                        "Error: Access denied! You need to be authorized to perform this action!",
                        "    at /home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/helpers/auth-middleware.js:13:1",
                        "    at dispatchHandler (/home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/resolvers/helpers.js:82:1)"
                    ]
                }
            }
        }],
        "data": null
    },
    "status": 200,
    "headers": {
        "access-control-expose-headers": "WWW-Authenticate,Server-Authorization",
        "connection": "keep-alive",
        "vary": "origin",
        "access-control-allow-credentials": "true",
        "content-length": "601",
        "date": "Tue, 14 Jun 2022 15:32:37 GMT",
        "content-type": "application/json; charset=utf-8",
        "cache-control": "no-cache",
        "keep-alive": "timeout=5"
    },
    "config": {
        "transitional": {
            "silentJSONParsing": true,
            "forcedJSONParsing": true,
            "clarifyTimeoutError": false
        },
        "transformRequest": [
            null
        ],
        "transformResponse": [
            null
        ],
        "timeout": 0,
        "xsrfCookieName": "XSRF-TOKEN",
        "xsrfHeaderName": "X-XSRF-TOKEN",
        "maxContentLength": -1,
        "maxBodyLength": -1,
        "env": {
            "FormData": null
        },
        "headers": {
            "Accept": "application/json, text/plain, */*",
            "Content-Type": "application/json",
            "Authorization": "Bearer + MY JWT TOKEN GOES HERE",
            "pushnotificationtoken": ""
        },
        "baseURL": "http://10.0.2.2:3000/development/",
        "method": "post",
        "url": "graphql",
        "data": "{\"query\":\"query getAllOrders {\\n  getAllOrders {\\n    id\\n    status\\n    table\\n    items {\\n      id\\n      description\\n      quantity\\n      priceCents\\n    }\\n    totalOrderPriceCents\\n    createdAt\\n  }\\n}\\n\"}"
    },
    "request": {
        "UNSENT": 0,
        "OPENED": 1,
        "HEADERS_RECEIVED": 2,
        "LOADING": 3,
        "DONE": 4,
        "readyState": 4,
        "status": 200,
        "timeout": 0,
        "withCredentials": true,
        "upload": {},
        "_aborted": false,
        "_hasError": false,
        "_method": "POST",
        "_perfKey": "network_XMLHttpRequest_http://10.0.2.2:3000/development/graphql",
        "_response": "{\"errors\":[{\"message\":\"Acesso não autorizado\",\"locations\":[{\"line\":2,\"column\":3}],\"path\":[\"getAllOrders\"],\"extensions\":{\"code\":\"INTERNAL_SERVER_ERROR\",\"exception\":{\"stacktrace\":[\"Error: Access denied! You need to be authorized to perform this action!\",\"    at /home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/helpers/auth-middleware.js:13:1\",\"    at dispatchHandler (/home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/resolvers/helpers.js:82:1)\"]}}}],\"data\":null}\n",
        "_url": "http://10.0.2.2:3000/development/graphql",
        "_timedOut": false,
        "_trackingName": "unknown",
        "_incrementalEvents": false,
        "responseHeaders": {
            "access-control-expose-headers": "WWW-Authenticate,Server-Authorization",
            "Connection": "keep-alive",
            "vary": "origin",
            "access-control-allow-credentials": "true",
            "content-length": "601",
            "Date": "Tue, 14 Jun 2022 15:32:37 GMT",
            "content-type": "application/json; charset=utf-8",
            "cache-control": "no-cache",
            "Keep-Alive": "timeout=5"
        },
        "_requestId": null,
        "_headers": {
            "accept": "application/json, text/plain, */*",
            "content-type": "application/json",
            "authorization": "Bearer + jwt goes here",
            "pushnotificationtoken": ""
        },
        "_responseType": "",
        "_sent": true,
        "_lowerCaseResponseHeaders": {
            "access-control-expose-headers": "WWW-Authenticate,Server-Authorization",
            "connection": "keep-alive",
            "vary": "origin",
            "access-control-allow-credentials": "true",
            "content-length": "601",
            "date": "Tue, 14 Jun 2022 15:32:37 GMT",
            "content-type": "application/json; charset=utf-8",
            "cache-control": "no-cache",
            "keep-alive": "timeout=5"
        },
        "_subscriptions": [],
        "responseURL": "http://10.0.2.2:3000/development/graphql"
    }
}

The same request using Insomnia:

insomnia

Insomnia Timeline:

insomnia timeline

Insomnia Header
enter image description here

console.log(response.request):



{
  "UNSENT": 0,
  "OPENED": 1,
  "HEADERS_RECEIVED": 2,
  "LOADING": 3,
  "DONE": 4,
  "readyState": 4,
  "status": 200,
  "timeout": 0,
  "withCredentials": true,
  "upload": {},
  "_aborted": false,
  "_hasError": false,
  "_method": "POST",
  "_perfKey": "network_XMLHttpRequest_http://10.0.2.2:3000/development/graphql",
  "_response": "{\"errors\":[{\"message\":\"Acesso não autorizado\",\"locations\":[{\"line\":2,\"column\":3}],\"path\":[\"getAllOrders\"],\"extensions\":{\"code\":\"INTERNAL_SERVER_ERROR\",\"exception\":{\"stacktrace\":[\"Error: Access denied! You need to be authorized to perform this action!\",\"    at /home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/helpers/auth-middleware.js:13:1\",\"    at dispatchHandler (/home/agostinho/Documents/MY-MOBILE-PROJECT/v1/MY-MOBILE-PROJECT-back-end-2020/.webpack/service/src/webpack:/node_modules/type-graphql/dist/resolvers/helpers.js:82:1)\"]}}}],\"data\":null}\n",
  "_url": "http://10.0.2.2:3000/development/graphql",
  "_timedOut": false,
  "_trackingName": "unknown",
  "_incrementalEvents": false,
  "responseHeaders": {
    "access-control-expose-headers": "WWW-Authenticate,Server-Authorization",
    "Connection": "keep-alive",
    "vary": "origin",
    "access-control-allow-credentials": "true",
    "content-length": "601",
    "Date": "Tue, 14 Jun 2022 17:42:39 GMT",
    "content-type": "application/json; charset=utf-8",
    "cache-control": "no-cache",
    "Keep-Alive": "timeout=5"
  },
  "_requestId": null,
  "_headers": {
    "accept": "application/json, text/plain, */*",
    "content-type": "application/json",
    "authorization": "Bearer eyJ........",
    "pushnotificationtoken": ""
  },
  "_responseType": "",
  "_sent": true,
  "_lowerCaseResponseHeaders": {
    "access-control-expose-headers": "WWW-Authenticate,Server-Authorization",
    "connection": "keep-alive",
    "vary": "origin",
    "access-control-allow-credentials": "true",
    "content-length": "601",
    "date": "Tue, 14 Jun 2022 17:42:39 GMT",
    "content-type": "application/json; charset=utf-8",
    "cache-control": "no-cache",
    "keep-alive": "timeout=5"
  },
  "_subscriptions": [],
  "responseURL": "http://10.0.2.2:3000/development/graphql"
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

路还长,别太狂 2025-02-14 21:03:42

我发现了错误。这是我授权者背景下的行为!

失眠症正在用a为大写,但是,Axios用授权, a a 作为小写。

我需要调试后端,因此我使用以下内容来处理:

const授权= ctx.event.headers.authorization || ctx.event.headers.authorization

因此,我的授权者上下文将在两种情况下处理。

最终代码:

export default function context (ctx: any): any {
  const Authorization = ctx.event.headers.Authorization || ctx.event.headers.authorization
  if (typeof Authorization !== 'undefined' && Authorization.indexOf('Bearer') > -1) {
     try {
        const AuthorizationToken = Authorization.replace('Bearer ', '')
        const customer = jwt.verify(AuthorizationToken, process.env.JWT_CUSTOMER_SECRET) as CustomerContext

        customer.devicePushNotificationToken = ctx.event.headers.pushnotificationtoken

        return { customer }
     } catch (err) { }
  } else {
    return null
  }
}

I found the error. It was a behavior at my authorizer context!

The Insomnia was sending Authorization with the A as Uppercase, however, axios was sending authorization with the a as lowercase.

I needed to debug my backend, so I use the following to handle with that:

const Authorization = ctx.event.headers.Authorization || ctx.event.headers.authorization

Thus, my authorizer context will handle with two situations.

The final code:

export default function context (ctx: any): any {
  const Authorization = ctx.event.headers.Authorization || ctx.event.headers.authorization
  if (typeof Authorization !== 'undefined' && Authorization.indexOf('Bearer') > -1) {
     try {
        const AuthorizationToken = Authorization.replace('Bearer ', '')
        const customer = jwt.verify(AuthorizationToken, process.env.JWT_CUSTOMER_SECRET) as CustomerContext

        customer.devicePushNotificationToken = ctx.event.headers.pushnotificationtoken

        return { customer }
     } catch (err) { }
  } else {
    return null
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文