Javascript Web扩展标识令牌返回403
帐户信息: 用户名:testAccount 密码1234 我使用的是Firefox开发者版,因为它支持身份调用。 我收到来自验证的403错误。“TypeError:尝试获取资源时出现NetworkError。”“403禁止”我做错了什么,阻止它进入下一步 Manifest.json文件内容Javascript Web扩展标识令牌返回403,javascript,firefox-addon-webextensions,Javascript,Firefox Addon Webextensions,帐户信息: 用户名:testAccount 密码1234 我使用的是Firefox开发者版,因为它支持身份调用。 我收到来自验证的403错误。“TypeError:尝试获取资源时出现NetworkError。”“403禁止”我做错了什么,阻止它进入下一步 Manifest.json文件内容 { "manifest_version": 2, "name": "Lewp", "applications": { "gecko": { "id": "addon@
{
"manifest_version": 2,
"name": "Lewp",
"applications": {
"gecko": {
"id": "addon@lewp.com"
}
},
"version": "1.0",
"description": "Test project to check Oauth2",
"icons": {
"48": "icons/link-48.png"
},
"browser_action": {
"browser_style": true,
"default_icon": {
"16": "icons/link-48.png",
"32": "icons/link-48.png"
},
"default_title": "Whereami?"
},
"permissions": [
"activeTab",
"alarms",
"bookmarks",
"browsingData",
"contextMenus",
"contextualIdentities",
"cookies",
"downloads",
"downloads.open",
"history",
"identity",
"idle",
"management",
"notifications",
"nativeMessaging",
"sessions",
"storage",
"tabs",
"topSites",
"webNavigation",
"webRequest",
"webRequestBlocking"
],
"options_ui": {
"page": "settings/options.html"
},
"background": {
"scripts": ["core.js", "settings/background-script.js", "settings/jquery-3.1.1.min.js"]
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"exclude_matches": ["*://*.lewp.com/*", "*://*.google.com/*"],
"js": ["settings/borderify.js"]
}
],
"default_locale": "en"
}
{
“清单版本”:2,
“名称”:“Lewp”,
“应用程序”:{
“壁虎”:{
“id”:”addon@lewp.com"
}
},
“版本”:“1.0”,
“说明”:“检查Oauth2的测试项目”,
“图标”:{
“48”:“icons/link-48.png”
},
“浏览器操作”:{
“浏览器样式”:正确,
“默认_图标”:{
“16”:“icons/link-48.png”,
“32”:“icons/link-48.png”
},
“默认标题”:“我在哪里?”
},
“权限”:[
“活动标签”,
“警报”,
“书签”,
“浏览数据”,
“上下文菜单”,
“背景特性”,
“饼干”,
“下载”,
“下载。打开”,
“历史”,
“身份”,
“闲置”,
“管理”,
“通知”,
“nativeMessaging”,
“会议”,
“存储”,
“标签”,
“表土”,
“网络导航”,
“网络请求”,
“webRequestBlocking”
],
“选项界面”:{
“页面”:“设置/选项.html”
},
“背景”:{
“脚本”:[“core.js”、“settings/background script.js”、“settings/jquery-3.1.1.min.js”]
},
“内容脚本”:[
{
“匹配项”:[“”],
“排除匹配项”:[“*://*.lewp.com/*”,“*://*.google.com/*”,
“js”:[“settings/borderify.js”]
}
],
“默认语言环境”:“en”
}
background-scripts.js
function onError(error) {
console.log(`Error: ${error}`);
}
const REDIRECT_URL = browser.identity.getRedirectURL();
const CLIENT_ID = "f3dddddasdfaasdfvfdggfsfdg";
const CLIENT_SECRET = "4c7f6f8fa93d59c45502c0ae8c4a95b";
const AUTH_URL =
`http://lewp.com/oauth/authorize
?client_id=${CLIENT_ID}
&response_type=code
&redirect_uri=${encodeURIComponent(browser.identity.getRedirectURL())}`;
const VALIDATION_BASE_URL="http://lewp.com/oauth/access_token";
function extractAccessToken(redirectUri) {
let m = redirectUri.match(/[#\?](.*)/);
if (!m || m.length < 1)
return null;
let params = new URLSearchParams(m[1].split("#")[0]);
return params.get("code");
}
function extractState(redirectUri) {
let m = redirectUri.match(/[#\?](.*)/);
if (!m || m.length < 1)
return null;
let params = new URLSearchParams(m[1].split("#")[0]);
return params.get("state");
}
/**
Validate the token contained in redirectURL.
This follows essentially the process here:
https://developers.google.com/identity/protocols/OAuth2UserAgent#tokeninfo-validation
- make a GET request to the validation URL, including the access token
- if the response is 200, and contains an "aud" property, and that property
matches the clientID, then the response is valid
- otherwise it is not valid
Note that the Google page talks about an "audience" property, but in fact
it seems to be "aud".
*/
function validate(redirectURL) {
const accessToken = extractAccessToken(redirectURL);
const state = extractState(redirectURL);
if (!accessToken) {
throw "Authorization failure";
} else {
let accessTokenSetting = {
accessToken: accessToken
}
// store the objects
let setting = browser.storage.local.set({accessTokenSetting});
// just check for errors
setting.then(null, onError);
let accessTokenGot = browser.storage.local.get("accessTokenSetting");
accessTokenGot.then(onGotToken, onError);
function onGotToken(item) {
console.log(item.accessTokenSetting.accessToken);
}
}
const validationURL = `${VALIDATION_BASE_URL}?code=${accessToken}&state=${state}`;
const validationRequest = new Request(VALIDATION_BASE_URL, {
method: "POST",
body : [
'grant_type=authorization_code',
'client_id='+ CLIENT_ID,
'client_secret='+ CLIENT_SECRET,
'redirect_uri='+ encodeURIComponent(REDIRECT_URL),
'code='+ accessToken
].join('&'),
headers: {"content-type": "application/x-www-form-urlencoded",
"code": accessToken}
// state: "432123",
// dataType: "json",
// contentType: "json"
});
function checkResponse(response) {
return new Promise((resolve, reject) => {
if (response.status != 200) {
console.log('Token validation error');
reject("Token validation error");
}
response.json().then((json) => {
// if (json.client_id && (json.client_id === CLIENT_ID)) {
if (json.access_token) {
resolve(accessToken);
} else {
console.log("Token validation error");
reject("Token validation error");
}
});
});
}
return fetch(validationRequest)
.then(checkResponse)
.catch(logError);
}
/**
Authenticate and authorize using browser.identity.launchWebAuthFlow().
If successful, this resolves with a redirectURL string that contains
an access token.
*/
//'http://localhost:8000/oauth/authorize?client_id=f3dddddasdfaasdfvfdggfsfdg&redirect_uri=https://e188f182e3ca96050362eff7355ace5274d6f59e.extensions.allizom.org/&response_type=code'
function authorize() {
if(typeof chrome == "undefined")
return browser.identity.launchWebAuthFlow({
interactive: true,
url: AUTH_URL
});
else
return new Promise(function(resolve,reject){
browser.identity.launchWebAuthFlow({
interactive: true,
url: AUTH_URL
}, (responseUrl)=>{
if(chrome.runtime.lastError)
reject(chrome.runtime.lastError);
else
resolve(responseUrl);
});
})
}
function getAccessToken() {
return authorize().then(validate).catch(logError);
}
function logError(error) {
console.error(`Error: ${error} `);
}
/**
When the button's clicked:
- get an access token using the identity API
- use it to get the user's info
- show a notification containing some of it
*/
// getAccessToken()
// .then(notifyUser)
// .catch(logError);
/*
Log that we received the message.
Then display a notification. The notification contains the URL,
which we read from the message.
*/
function notify(message) {
var title = browser.i18n.getMessage("notificationTitle");
var content = browser.i18n.getMessage("notificationContent", message.url);
browser.notifications.create({
"type": "basic",
"iconUrl": browser.extension.getURL("icons/link-48.png"),
"title": title,
"message": content
});
}
/*
Assign `notify()` as a listener to messages from the content script.
*/
browser.runtime.onMessage.addListener(notify);
function sendMessageToTabs(tabs) {
for (let tab of tabs) {
browser.tabs.sendMessage(
tab.id,
{greeting: "Hi from background script"}
).then(response => {
console.log("Message from the content script:");
console.log(response.response);
}).catch(onError);
}
}
//actual start to code
//set global data variable
var data = {};
function getAccessToken() {
return authorize().then(validate).catch(logError);
}
function onGotToken(item) {
var promise = new Promise(function(resolve, reject){
data.token = item.accessTokenSetting.accessToken;
resolve();
});
return promise;
};
function fetchToken(item) {
//getAccessToken from backend need to modify it so it waits until after
//call to get Access Token
var promise = new Promise(function(resolve, reject){
var accessTokenGot = browser.storage.local.get("accessTokenSetting");
accessTokenGot.then(onGotToken, logError).then(resolve, reject);
});
return promise;
}
function fetchLewps(item) {
var promise = new Promise(function(resolve, reject){
resolve();
});
return promise;
}
function fetchLewpsAPI(item) {
var promise = new Promise(function(resolve, reject){
var url = 'http://lewp.com/api?access_token='+data.token;
fetch(url, {
method: 'GET',
headers: { "authorization": "Bearer "+data.token,
"content-type": "application/x-www-form-urlencoded"}
})
.then(json)
.then(function (data) {
console.log('Request succeeded with JSON response', data);
resolve();
})
.catch(function (error) {
console.log('Request failed', error);
});
});
return promise;
}
//on click of browser toolbar button
browser.browserAction.onClicked.addListener(() => {
//get authorized
getAccessToken()
.then(fetchToken)
.then(fetchLewps)
.then(fetchLewpsAPI)
.catch(logError);
//filler that sends notification
browser.tabs.query({
currentWindow: true,
active: true
}).then(sendMessageToTabs).catch(onError);
});
函数onError(错误){
log(`Error:${Error}`);
}
const REDIRECT_URL=browser.identity.getRedirectURL();
const CLIENT_ID=“F3DDDASDFAASDFVFDGGFSFDG”;
const CLIENT_SECRET=“4c7f6f8fa93d59c45502c0ae8c4a95b”;
常量验证URL=
`http://lewp.com/oauth/authorize
?客户机\u id=${client\u id}
&响应类型=代码
&重定向_uri=${encodeURIComponent(browser.identity.getRedirectURL())}`;
常量验证\u基\u URL=”http://lewp.com/oauth/access_token";
函数extractAccessToken(重定向URI){
设m=redirectUri.match(/[\?](.*)/);
如果(!m | | m.长度<1)
返回null;
设params=newURLSearchParams(m[1]。拆分(“#”)为[0]);
返回参数get(“代码”);
}
函数提取状态(重定向URI){
设m=redirectUri.match(/[\?](.*)/);
如果(!m | | m.长度<1)
返回null;
设params=newURLSearchParams(m[1]。拆分(“#”)为[0]);
返回参数get(“state”);
}
/**
验证重定向URL中包含的令牌。
这基本上遵循以下过程:
https://developers.google.com/identity/protocols/OAuth2UserAgent#tokeninfo-验证
-向验证URL发出GET请求,包括访问令牌
-如果响应为200,并且包含“aud”属性,则
匹配clientID,则响应有效
-否则无效
请注意,Google页面谈论的是“访问者”属性,但实际上
似乎是“澳元”。
*/
函数验证(重定向URL){
const accessToken=extractAccessToken(重定向URL);
const state=extractState(重定向URL);
如果(!accessToken){
抛出“授权失败”;
}否则{
让accessTokenSetting={
accessToken:accessToken
}
//存储对象
let setting=browser.storage.local.set({accessTokenSetting});
//只需检查错误
设置。然后(null,onError);
让AccessTokenGet=browser.storage.local.get(“accessTokenSetting”);
然后(onGotToken,onError);
onGotToken功能(项目){
log(item.accessTokenSetting.accessToken);
}
}
const validationURL=`${VALIDATION\u BASE\u URL}?code=${accessToken}&state=${state}`;
const validationRequest=新请求(验证\u基\u URL{
方法:“张贴”,
正文:[
“授权类型=授权代码”,
'客户id='+客户id,
'client_secret='+client_secret,
'redirect_uri='+encodeURIComponent(redirect_URL),
'代码='+accessToken
].join(“&”),
标题:{“内容类型”:“application/x-www-form-urlencoded”,
“代码”:accessToken}
//国家:“432123”,
//数据类型:“json”,
//contentType:“json”
});
功能检查响应(响应){
返回新承诺((解决、拒绝)=>{
如果(response.status!=200){
log(“令牌验证错误”);
拒绝(“令牌验证错误”);
}
response.json()。然后((json)=>{
//if(json.client\u id&&(json.client\u id===client\u id)){
if(json.access\u令牌){
解析(accessToken);
}否则{
日志(“令牌验证错误”);
拒绝(“令牌验证错误”);
}
});
});
}
返回获取(validationRequest)
.然后(检查响应)
.catch(logError);
}
/**
使用browser.identity.launchWebAuthFlow()进行身份验证和授权。
如果成功,将使用包含
访问令牌。
*/
//'http://localhost:8000/oauth/authorize?client_id=f3dddddasdfaasdfvfdggfsfdg&redirect_uri=https://e188f182e3ca96050362eff7355ace5274d6f59e.extensions.allizom.org/&response_type=code'
函数authorize(){
如果(chrome类型==“未定义”)
返回browser.identity.launchWebAuthFlow({
互动:没错,
url:AUTH_url
});
其他的
返回新承诺(功能(解决、拒绝){
browser.identity.launchWebAuthFlow({
互动:没错,
url:AUTH_url
},(responseUrl)=>{
if(chrome.runtime.lastError)
拒绝(chrome.runtime.lastError);
其他的
决心(责任);
});
})
}
函数getAccessToken(){
返回authorize().then(validate).catch(logError);
}
函数日志错误(错误){
console.error(`error:${error}`);
}
/**
单击按钮时:
-使用identity API获取访问令牌
-使用它来获取用户的信息
-显示包含部分内容的通知
*/