类似的问题是由其他人(here)提出的,但没有得到正确答案。因为这对我来说是基本而重要的(也许也适用于其他人),我试着在这里问一下。我在服务器端使用Node.js + Express + EJS。我努力通过在服务器上使用jsonwebtoken和在Web浏览器上使用jQuery的ajax-jsonp来使令牌认证成功。现在,在令牌被授予并存储在浏览器端的sessionStorage中之后,我可以使用请求头中包含的令牌发起另一个ajax请求,以获取用户的配置文件并将其显示在“当前”页面的某个位置。但我想要的是显示一个新的网页来显示用户的个人资料,而不是在“当前”页面(网站的主/索引页面)中显示它。问题是:
或者,我们是否应该说令牌机制比普通网页身份验证(Web浏览器提供有限的API)更适合API身份验证?
我认为如果我们想要将令牌机制用作一般身份验证,这个问题的答案很重要,因为在网站场景中,内容主要被组织为服务器上的网页,而客户端上的API则由浏览器。
通过纯粹的猜测,可能有另一种方式,ajax成功回调从当前页面用服务器的响应创建一个新页面,但我不知道如何实现这一点。
通过调用bellow代码成功返回 customer_profile.ejs 中的HTML内容,但客户端ajax(显然)拒绝了它。
exports.customer_profile = function (req, res) {
var token = req.headers.token;
var public_key = fs.readFileSync(path.resolve() + '/cert/public_key.pem');
var decoded = jwt.verify(token, public_key);
var sql = 'SELECT * FROM customer WHERE username = "' + decoded.sub + '"';
util.conn.query(sql, function (err, rows) {
if (!err) {
for (var i = 0; i < rows.length; i++) {
res.render('customer_profile', {customer_profile: rows[i]});
break;
}
}
});
};
答案 0 :(得分:0)
我也在尝试找到解决方案。请注意,我正在使用Firebase来实现某些功能,但是我会尽力记录逻辑。
到目前为止,我能弄清的是以下内容:
// landing.js - main page script snippet
function loadPage(path) {
// Get current user's ID Token
firebase.auth().currentUser.getIdToken()
.then(token => {
// Make a fetch request to 'path'
return fetch(`${window.location.origin}/${document.documentElement.lang}/${path}`, {
method: 'GET',
headers: {'X-Firebase-ID-Token': token} // Adds unverified token to a custom header
});
})
.then(response => {
// As noted below, this part I haven't solved yet.
// TODO: Open response as new webpage instead of displaying as data in existing one
return response.text();
})
.then(text => {
console.log(text);
})
.catch(error => {
console.log(error);
});
}
// app.js - main Express application server-side file
// First of all, I set up middleware on my application (and all other setup).
// getLocale - language negotiation.
// getContext - auth token verification if it is available and appends it to Request object for convenience
app.use('/:lang([a-z]{2})?', middleware.getLocale, middleware.getContext, routes);
// Receives all requests on optional 2 character route, runs middleware then passes to router "routes"
// middleware/index.js - list of all custom middleware functions (only getContext shown for clarity)
getContext: function(req, res, next) {
const idToken = req.header('X-Firebase-ID-Token'); // Retrieves token from header
if(!idToken) {
return next(); // Passes to next middleware if no token, terminates further execution
}
admin.auth().verifyIdToken(idToken, true) // If token provided, verify authenticity (Firebase is kind enough to do it for you)
.then(token => {
req.decoded_token = token; // Append token to Request object for convenience in further middleware
return next(); // Pass on further
})
.catch(error => {
console.log('Request not authorized', 401, error)
return next(); // Log error to server console, pass to next middleware (not interested in failing the request here as app can still work without token)
});
}
// routes/index.js - main router for my application mounted on top of /:lang([a-z]{2})? - therefore routes are now relative to it
// here is the logic for displaying or not displaying the page to the user
router.get('/console', middleware.getTranslation('console'), (req, res) => {
if(req.decoded_token) { // if token was verified successfully and is appended to req
res.render('console', responseObject); // render the console.ejs with responseObject as the data source (assume for now that it contains desired DB data)
} else {
res.status(401).send('Not authorized'); // else send 401 to user
}
});
如您所见,我能够对代码进行模块化,并使之简洁明了,并且可以使用自定义中间件。现在是一个有效的API,使用身份验证和受限访问从服务器返回数据
我尚未解决的问题:
如上所述,该解决方案使用提取API,请求的结果是来自服务器(html)的数据,而不是新页面的数据(即,在跟随锚链接时)。这意味着现在使用此代码的唯一方法是使用DOM操作并将响应设置为该页面的innerHTML。 MDN建议您设置“ Location”标头,该标头将在浏览器中显示一个新URL(您希望指示的URL)。这意味着您实际上已经实现了您和我都想要的东西,但是如果您知道我的意思,那么我仍然无法像浏览器跟随链接时一样展示如何展示它。
无论如何,请让我知道您对此的想法,以及您是否能够从我还没有解决的部分中解决它