使用 JWT 的承载方案的身份验证标头
Posted
技术标签:
【中文标题】使用 JWT 的承载方案的身份验证标头【英文标题】:Authentication header using bearer scheme for JWT 【发布时间】:2018-05-04 01:58:24 【问题描述】:我正在使用 Express、Passport 和 jsonwebtoken 在 NodeJS 中为网站构建身份验证系统。 我到处搜索,但找不到问题的解决方案。
现在我有一个身份验证控制器:
module.exports = function()
var strategy = new BearerStrategy(params, function(payload, done)
var decodedToken = jwtDecode(payload)
db.default.Account.find(where: id: decodedToken.id).then(account =>
if (account)
return done(null,
id: account.id,
role: account.role
)
else
return done(new Error("User not found"), null)
)
)
passport.use(strategy)
return
initialize: function()
return passport.initialize()
,
authenticate: function()
return passport.authenticate("bearer", cfg.jwtSession)
我在其中使用 BearerStrategy 并且此代码有效,因为我的 /login 路由为用户创建了一个令牌并返回该令牌
accountController.post("/login", function(req, res)
if (req.body.email && req.body.password)
var accEmail = req.body.email
var accPassword = req.body.password
db.default.Account.find(where: email: accEmail, password:
accPassword).then(account =>
if (account)
var payload =
id: account.id,
role: account.role
var token = jwt.sign(payload, cfg.jwtSecret)
console.log(token)
res.status(200).json(
token: 'Bearer ' + token
)
else
res.sendStatus(401)
)
else
res.sendStatus(401)
)
如果我使用 Postman 发送一个 HTTP 请求来尝试访问路由 /account 并且我将创建的令牌设置为标头,那么一切正常。
accountController.get('/account', auth.authenticate('bearer', session: false ), function(req, res)
res.status(200).render('pages/homepage')
)
我无法回答的问题是: 用 res.json(token: token) 发回令牌是不够的,令牌需要存储在某个地方,对吧?我应该如何使用 RestAPI 存储令牌,此外,我应该如何在每个请求的 HTTP 标头中从客户端发送令牌?
我愿意接受有关如何在存储和发送 JWT 之间建立这种连接的建议(因为 JWT 的生成和验证工作) 谢谢
【问题讨论】:
【参考方案1】:是的,这样发送令牌就足够了。您只需要确保客户端以某种方式收到令牌。在您的特定情况下,客户端将向 /login
端点发送 POST 请求,并从对请求的响应中读取令牌。在半伪代码中(客户端 javascript):
http.post('/login', (response) =>
let token = response.split(' ')[1];
);
客户端存储令牌。它存储在localStorage、sessionStorage 或cookie 中。各种存储位置都有pros and cons。必须对客户端进行编程以将其存储在这些地方之一,而服务器根本不存储它。如果您使用的是 Angular 或 React 等前端框架,您可以使用 Google 和搜索词(例如“angular、jwt、 storage”)找到大量信息和示例。如果您使用的是 vanilla JS,您可以按照提供的链接中的示例进行操作。基于上面的半伪代码构建:
http.post('/login', (response) =>
let token = response.split(' ')[1];
localStorage.setItem('token', token);
);
令牌在名为授权的 HTTP 标头中与每个请求一起发送。标头应具有以下格式
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
眼睛...东西是实际的标记。在您的情况下,您可能必须使用 bearer(非大写 b),因为您已将 Passport 设置为这样。您也可以在代码中将其设为 auth.authenticate('Bearer', ...
以使其更“正确”。在较旧的文档和博客文章中,您经常可以看到 JWT 而不是 Bearer,但这并不真正遵循事实上的标准。
如果您以这种方式发送,Passport 应该可以正确读取令牌。
如何在客户端添加Authorization头取决于你是否使用框架,以及客户端是否是浏览器。如果您使用的是香草 JS,您可以阅读 this 链接。如果您使用的是框架,您可以谷歌“设置授权标头,角度”或类似的东西。官方文档和博客文章中通常都有大量信息。如果您使用的是前端框架,则添加 Authorization 字段的代码部分通常称为 auth 拦截器。拦截器有点像中间件。
最后,你正在写这个:
我应该如何使用 RestAPI 存储令牌...
REST 并不真正关心令牌的存储方式。它在客户端完成,与 REST 无关。但是,REST 关心端点的名称。如果/login
是动词,它真的是正确的名称吗?问题被提出并回答here。
【讨论】:
以上是关于使用 JWT 的承载方案的身份验证标头的主要内容,如果未能解决你的问题,请参考以下文章
.Net SignalR 在还配置了 Cookie 身份验证时使用 JWT 承载身份验证
在 ASP.Net 应用程序上结合 ADFS 身份验证和 JWT 承载