如何通过 Header 传递 JWT 并通过 Sails.js 中的服务器端视图检索数据
How to pass JWT via Header and retrieve data through Server Side Views in Sails.js
后端:Sails.js
我已经为 REST API 实施了 JSON Web 令牌,其中所有 AJAX 请求从 front-end 到各种控制器的操作 return 数据 res.json(data);
仅当它通过授权 Header 收到正确的 JWT 时。它按预期工作。
现在,我已经使用 <%= name =>
使用 EJS 创建了一个视图,现在控制器具有详细信息 res.view('/home', {name: "Bill"} );
并将路由也配置为指向相应的控制器。
我如何通过从具有属性 <%= name =>
的服务器端视图使用已发布的 JWT(存储在 localStorage 中)进行身份验证,从控制器检索 "name"
谢谢。
代码:
views/index.ejs
<%= name =>
api/controllers/UsersController.js
info: function(req, res) {
var userId = req.token;
Users.findOne(userId).exec(function(err, profile) {
if(err) {
res.json(err);
} else {
res.view('index',{
name: profile.name,
});
}
});
},
api/policies/tokenAuth.js
module.exports = function(req, res, next) {
var token;
if (req.headers && req.headers.authorization) {
var parts = req.headers.authorization.split(' ');
if (parts.length == 2) {
var scheme = parts[0],
credentials = parts[1];
if (/^Bearer$/i.test(scheme)) {
token = credentials;
}
} else {
return res.json(401, {err: 'Format is Authorization: Bearer [token]'});
}
} else if (req.param('token')) {
token = req.param('token');
delete req.query.token;
} else {
return res.json(401, {err: 'No Authorization header was found'});
}
sailsTokenAuth.verifyToken(token, function(err, token) {
if (err) return res.json(401, {err: 'Please Logout and Login again!'});
req.token = token;
next();
});
};
api/services/sailsTokenAuth.js
var jwt = require('jsonwebtoken');
module.exports.issueToken = function(payload) {
var token = jwt.sign(payload, process.env.TOKEN_SECRET || "xxxxxxx");
return token;
};
module.exports.verifyToken = function(token, verified) {
return jwt.verify(token, process.env.TOKEN_SECRET || "xxxxxxx", {}, verified);
};
config/routes.js
module.exports.routes = {
'/': {
controller: 'UsersController',
action: 'info'
},
};
解决方案:
要使用 JWT 作为从客户端浏览器到服务器的身份验证因素,可以使用 localStorage 或 session cookie。由于在服务器中更容易实现,我最终将范围缩小到使用 cookie。
验证用户身份后,将 JWT 存储在客户端浏览器中,
res.cookie('jwttoken', sailsTokenAuth.issueToken(profile.name));
然后可以使用 req.cookies.jwttoken
检索它并通过服务 (jwt.verify) 验证它以通过 res.json
或 res.view
[=25 访问请求的信息=]
看不到您的任何代码,因为没有提供,但假设您设置了自定义策略 api/policies/jwt.js 等,并在其中您检查每个请求的 JWTToken。类似的东西(为简单起见忽略任何错误处理):
module.exports = function (req, res, next) {
var token = req.headers.authorization.split(' ')[1];
var payload = jwt.decode(token, config.TOKEN_SECRET);
req.userId = payload.sub;
next();
};
请注意我是如何将 userId 附加到 req object (req.userId = payload.sub;).这意味着在您的 controller 中,您将有权访问 userId(或者在您的情况下,无论您使用什么 ID 来识别您的登录用户等),因为您可以简单地从传入的 req object 中引用它。
显然,您对 JWT 政策的实施可能会有所不同,但只需将其自定义为上述内容即可。如果您实际上将 name 保留在 jwt 令牌本身中(看不到您的实现),那么只需将其附加到 req object(不需要模型查找)。
获得所需的 name 后,将其传递给您的视图(正如您目前正在使用上面的硬编码值 Bill 所做的那样。
根据更新的问题进行更新
因此,根据您的评论和更新的问题,您已经设法从 JWT 令牌中提取配置文件信息,并从模型查找中获取所需的配置文件信息。您现在无法在 EJS 视图中显示该名称。
所以你可以这样实现:
控制器:
res.view('index', {
name: profile.name
}
注意我删除了 profile.name 之后的逗号;)
如果您使用的是模板引擎,config/views.js 应设置为 "ejs"。
其余看起来不错。至少,符合我的预期。
您最好的选择是显式使用调试器,或者至少 console.log 语句直到 controller.info 方法 returns 之前,并确保 profile.name 按预期设置。如果你做到这一点,那么你就会知道问题出在以某种方式查看的路由上。
您可以尝试在视图下创建一个子文件夹并重命名视图文件(索引有点特殊..)。做一些像 views/xxx/yyy.ejs
也暂时注释掉你的 controller.info 方法,并用一些非常简单的东西代替它,比如:
res.view('xxx/yyy', {
name: 'bob'
});
根据进一步的用户反馈进一步更新
从你最后的评论来看,你的问题正在逐渐演变...
我认为您现在要说的是 Sails 代码都可以正常工作,并且使用 Postman 证明可以正常工作。但是在使用 Web 浏览器客户端时失败,因为您的客户端代码没有在 http header.
中传递正确的令牌信息
如果是这种情况,您需要在客户端上创建一个以编程方式应用 header 信息的拦截器。
例如。 (只是取自 Angular 工厂 authInterceptor 的片段,但此处未显示任何 angular 具体内容):
request: function (config) {
var token = authToken.getToken();
if (token) {
config.headers.Authorization = 'Bearer ' + token;
}
return config;
},
上面,根据请求,从本地存储(你说你正在工作)中检索 JWT,如果令牌存在,则 http headers 信息会使用授权更新 header 形式为'不记名令牌'。
我没有看过你的回购协议,老实说,我确实觉得我已经给了你很多信息。根据我提供的内容,也许再进行一些谷歌搜索/测试,您应该能够获得可行的解决方案。
后端:Sails.js
我已经为 REST API 实施了 JSON Web 令牌,其中所有 AJAX 请求从 front-end 到各种控制器的操作 return 数据 res.json(data);
仅当它通过授权 Header 收到正确的 JWT 时。它按预期工作。
现在,我已经使用 <%= name =>
使用 EJS 创建了一个视图,现在控制器具有详细信息 res.view('/home', {name: "Bill"} );
并将路由也配置为指向相应的控制器。
我如何通过从具有属性 <%= name =>
谢谢。
代码:
views/index.ejs
<%= name =>
api/controllers/UsersController.js
info: function(req, res) {
var userId = req.token;
Users.findOne(userId).exec(function(err, profile) {
if(err) {
res.json(err);
} else {
res.view('index',{
name: profile.name,
});
}
});
},
api/policies/tokenAuth.js
module.exports = function(req, res, next) {
var token;
if (req.headers && req.headers.authorization) {
var parts = req.headers.authorization.split(' ');
if (parts.length == 2) {
var scheme = parts[0],
credentials = parts[1];
if (/^Bearer$/i.test(scheme)) {
token = credentials;
}
} else {
return res.json(401, {err: 'Format is Authorization: Bearer [token]'});
}
} else if (req.param('token')) {
token = req.param('token');
delete req.query.token;
} else {
return res.json(401, {err: 'No Authorization header was found'});
}
sailsTokenAuth.verifyToken(token, function(err, token) {
if (err) return res.json(401, {err: 'Please Logout and Login again!'});
req.token = token;
next();
});
};
api/services/sailsTokenAuth.js
var jwt = require('jsonwebtoken');
module.exports.issueToken = function(payload) {
var token = jwt.sign(payload, process.env.TOKEN_SECRET || "xxxxxxx");
return token;
};
module.exports.verifyToken = function(token, verified) {
return jwt.verify(token, process.env.TOKEN_SECRET || "xxxxxxx", {}, verified);
};
config/routes.js
module.exports.routes = {
'/': {
controller: 'UsersController',
action: 'info'
},
};
解决方案:
要使用 JWT 作为从客户端浏览器到服务器的身份验证因素,可以使用 localStorage 或 session cookie。由于在服务器中更容易实现,我最终将范围缩小到使用 cookie。
验证用户身份后,将 JWT 存储在客户端浏览器中,
res.cookie('jwttoken', sailsTokenAuth.issueToken(profile.name));
然后可以使用 req.cookies.jwttoken
检索它并通过服务 (jwt.verify) 验证它以通过 res.json
或 res.view
[=25 访问请求的信息=]
看不到您的任何代码,因为没有提供,但假设您设置了自定义策略 api/policies/jwt.js 等,并在其中您检查每个请求的 JWTToken。类似的东西(为简单起见忽略任何错误处理):
module.exports = function (req, res, next) {
var token = req.headers.authorization.split(' ')[1];
var payload = jwt.decode(token, config.TOKEN_SECRET);
req.userId = payload.sub;
next();
};
请注意我是如何将 userId 附加到 req object (req.userId = payload.sub;).这意味着在您的 controller 中,您将有权访问 userId(或者在您的情况下,无论您使用什么 ID 来识别您的登录用户等),因为您可以简单地从传入的 req object 中引用它。
显然,您对 JWT 政策的实施可能会有所不同,但只需将其自定义为上述内容即可。如果您实际上将 name 保留在 jwt 令牌本身中(看不到您的实现),那么只需将其附加到 req object(不需要模型查找)。
获得所需的 name 后,将其传递给您的视图(正如您目前正在使用上面的硬编码值 Bill 所做的那样。
根据更新的问题进行更新
因此,根据您的评论和更新的问题,您已经设法从 JWT 令牌中提取配置文件信息,并从模型查找中获取所需的配置文件信息。您现在无法在 EJS 视图中显示该名称。
所以你可以这样实现:
控制器:
res.view('index', {
name: profile.name
}
注意我删除了 profile.name 之后的逗号;)
如果您使用的是模板引擎,config/views.js 应设置为 "ejs"。
其余看起来不错。至少,符合我的预期。
您最好的选择是显式使用调试器,或者至少 console.log 语句直到 controller.info 方法 returns 之前,并确保 profile.name 按预期设置。如果你做到这一点,那么你就会知道问题出在以某种方式查看的路由上。
您可以尝试在视图下创建一个子文件夹并重命名视图文件(索引有点特殊..)。做一些像 views/xxx/yyy.ejs
也暂时注释掉你的 controller.info 方法,并用一些非常简单的东西代替它,比如:
res.view('xxx/yyy', {
name: 'bob'
});
根据进一步的用户反馈进一步更新
从你最后的评论来看,你的问题正在逐渐演变...
我认为您现在要说的是 Sails 代码都可以正常工作,并且使用 Postman 证明可以正常工作。但是在使用 Web 浏览器客户端时失败,因为您的客户端代码没有在 http header.
中传递正确的令牌信息如果是这种情况,您需要在客户端上创建一个以编程方式应用 header 信息的拦截器。
例如。 (只是取自 Angular 工厂 authInterceptor 的片段,但此处未显示任何 angular 具体内容):
request: function (config) {
var token = authToken.getToken();
if (token) {
config.headers.Authorization = 'Bearer ' + token;
}
return config;
},
上面,根据请求,从本地存储(你说你正在工作)中检索 JWT,如果令牌存在,则 http headers 信息会使用授权更新 header 形式为'不记名令牌'。
我没有看过你的回购协议,老实说,我确实觉得我已经给了你很多信息。根据我提供的内容,也许再进行一些谷歌搜索/测试,您应该能够获得可行的解决方案。