Я пытаюсь создать расширение Chrome, используя реакцию, и позволяю пользователям входить с помощью Google на мой внутренний сервер, который работает с моим передним сервером веб-приложения. Я могу предложить пользователю войти в систему с помощью Google и получить код с помощью потока oauth2. Однако, когда я пытаюсь получить свой внутренний маршрут, я получаю следующую ошибку:
TypeError: Failed to fetch at background.js:20:7
Вот мой код расширения Chrome: manifest.json
{
"name": "my chrome extension",
"description": "my chrome extension description",
"version": "1.0.0",
"manifest_version": 3,
"author": "team creators",
"icons": {
"16" : "favicon.ico",
"48" : "favicon.ico",
"128" : "favicon.ico"
},
"action": {
"default_popup": "index.html",
"default_title": "my chrome extension"
},
"background": {
"service_worker": "background.js"
},
"oauth2": {
"client_id": "my client id",
"scopes": [
"openid",
"profile",
"email",
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/documents",
"https://www.googleapis.com/auth/contacts",
"https://www.googleapis.com/auth/contacts.readonly",
"https://www.googleapis.com/auth/contacts.other.readonly",
"https://mail.google.com/"
]
},
"content_security_policy": {
"script-src": ["'self'", "https://accounts.google.com", "'wasm-unsafe-eval'", "'inline-speculation-rules'", "http://localhost:*", "http://127.0.0.1:*"]
},
"permissions": [
"identity",
"nativeMessaging",
"tabs"
],
"host_permissions": [
"https://localhost:*/*",
"http://localhost:*/*"
]
}
index.html
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "utf-8" />
<link rel = "icon" href = "%PUBLIC_URL%/favicon.ico" />
<meta name = "viewport" content = "width=device-width, initial-scale=1" />
<meta name = "theme-color" content = "#000000" />
<meta
name = "description"
content = "Web site created using create-react-app"
/>
<link rel = "apple-touch-icon" href = "%PUBLIC_URL%/logo192.png" />
<link rel = "manifest" href = "%PUBLIC_URL%/manifest.json" />
<title>React App</title>
<script type = "text/javascript" src = "oauth2.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id = "root"></div>
</body>
</html>
oauth2.js
let clientId = 'my client id'
let redirectUri = `https://${chrome.runtime.id}.chromiumapp.org/`
let nonce = Math.random().toString(36).substring(2, 15)
function addClickEventToButton() {
const button = document.getElementById('google-login-button');
if (button) {
console.info("we get here 3");
button.addEventListener('click', function() {
const authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
authUrl.searchParams.set('client_id', clientId);
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('redirect_uri', redirectUri);
var manifest = chrome.runtime.getManifest();
authUrl.searchParams.set('scope', manifest.oauth2.scopes.join(' '));
// authUrl.searchParams.set('scope', 'openid profile email');
authUrl.searchParams.set('nonce', nonce);
// Show the consent screen after login.
authUrl.searchParams.set('prompt', 'consent');
chrome.identity.launchWebAuthFlow(
{
url: authUrl.href,
interactive: true,
},
async (redirectUrl) => {
if (redirectUrl) {
const codeRegex = /code=([^&]+)/;
const codeMatch = redirectUrl.match(codeRegex);
const code = codeMatch ? codeMatch[1] : null;
chrome.runtime.sendMessage({contentScriptQuery: "login", code: code}, function(response) {
console.info("reponse", response);
});
}
},
);
});
} else {
setTimeout(addClickEventToButton, 500);
}
}
document.addEventListener('DOMContentLoaded', function() {
addClickEventToButton();
});
фон.js
chrome.action.onClicked.addListener(function() {
chrome.tabs.create({url: 'index.html'});
console.info('action clicked');
});
chrome.runtime.onMessage.addListener(
async function(request, sender, sendResponse) {
if (request.contentScriptQuery == "login") {
console.info("getting request", request);
const url = "https://localhost:4000/google/auth/login";
fetch(url, { // errors here
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ code: request.code, isExtensionLogin: true }),
}).then(response => response.json())
.then(response => sendResponse(response))
.catch((err) => console.info("err", err))
return true;
}
});
Вот мой бэкэнд server.js с соответствующей информацией
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000,https://my-extension-id.chromiumapp.org/,chrome-extension://my-extension-id/"); // update to match the extension domain you will make the request from
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT,PATCH,DELETE");
res.setHeader(
"Access-Control-Allow-Headers",
"Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, Content-Type, Authorization, Access-Control-Request-Method, Access-Control-Request-Headers"
);
next();
});
маршрут: "https://localhost:4000/google/auth/логин"
const handleGoogleSignin = async (req, res) => {
try {
const isExtensionLogin = req.body.isExtensionLogin;
const { tokens } = await oauth2Client.getToken(req.body.code);
const { sub } = jwt.decode(tokens.id_token);
// check if user (google login user) exists
const googleIntegrated = await ThirdParty.findOne({
thirdPartyId: sub,
});
if (!googleIntegrated)
return res.status(404).json({ message: "Google Account not in DB" });
if (!googleIntegrated.isSignup)
return res.status(404).json({
message: "Google Account not associated with a login account",
});
// update google tokens
...
const user = await User.findById(googleIntegrated.userId);
const userToken = jwt.sign({ id: user._id }, process.env.JWT_SECRET);
res.status(200).json({ token: userToken, user });
} catch (err) {
res.status(409).json({ message: err.message });
}
};
Я нашел несколько вопросов по этой теме, но они мне не помогли Получение «TypeError: Failed to fetch», когда запрос на самом деле не завершился ошибкойВызов POST API возвращает ошибку CORS без https и ERR_CONNECTION_CLOSED безМанифест v3 получает данные из внешнего APIКак сделать кросс-оригинальный запрос в скрипте контента (в настоящее время заблокирован CORB, несмотря на правильные заголовки CORS)?
должно быть mode
но я все равно получаю ту же ошибку
@wOxxOm Я тоже изменился :*
все еще получаю ту же ошибку
@wOxxOm единственная другая проблема, которую я вижу, это content_security_policy
; однако я не уверен, что изменить
Отвечая на мой собственный вопрос:
Я должен быть "http://localhost:4000/google/auth/login", а не "https://localhost:4000/google/auth/login"
node
должен бытьmode
в параметрах выборки. Также попробуйте удалить:*
в host_permissions.