Nodejs jwt 鉴权问题请教

之前 nodejs 里习惯用 session 做鉴权,验证通过 req.session 直接保存就可以了。后续不管是浏览器请求还是 ajax 都会拿到 session 。 现在打算改成 jwt ,看 w3c 标准说是放到 header 的 Authorization 里边,鉴权逻辑已经改好了,但是传递这个头信息有点麻烦。 例如: /login 验证完,json 返回 token ,后续 ajax 请求可以自己加 header ,但是浏览器直接访问的页面并不会主动带 Authorization 信息,直接访问某个 url 例如:/profile 还是未鉴权。

有没有办法全局修改浏览器在当前网站中的 Authorization 头信息呢?


Nodejs jwt 鉴权问题请教

33 回复

jwt 鉴权一般只用于 API 上吧,没有直接访问 API URL 的场景。实在不行 access token 放 cookie 里也能接受


Authorization HEADER 这种授权模式本来就不是为了 Page 模式设计的,它主要是为了服务/服务通讯和 SPA 设计的。
没有办法全局设置浏览器的 Authorization, 一般如果的确需要使用顶级 GET 请求后端并附带权限,会再 query 字符串上添加 token=JwtToken 。如果你不是当页面,使用 cookie/session 模式才是更方便的。

我理解是请求接口才验证 jwt ,请求静态资源不校验 jwt 呀

封装一个全局请求方法带上 headers 参考 axios 全局拦截器

后端模拟前端登录

const template = <br> &lt;!DOCTYPE html&gt;<br> &lt;html lang="en"&gt;<br> &lt;head&gt;<br> &lt;meta charset="UTF-8"&gt;<br> &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;<br> &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;<br> &lt;title&gt;&lt;/title&gt;<br> &lt;/head&gt;<br> &lt;body&gt;<br> &lt;script&gt;<br> const channel = new BroadcastChannel('response');<br> channel.postMessage(${JSON.stringify(params)})<br> window.close();<br> &lt;/script&gt;<br> &lt;/body&gt;<br> &lt;/html&gt;<br>;

ctx.body = template;

直接放在 cookies 注意同源问题就行了。

jwt 为啥不能放 cookie 里,瞎搞扯,服务端为啥不能同时兼容 Authorization header 和 cookie 传递,这种标准本来就是推荐而已,既然不好用那不是给自己挖坑么

jwt 当然是放 cookie 里啊…
/login 验证完在 response 的 header 里加上 Set-Cookie: token=<jwtstring>

#7

确实,怎么传 jwt 是看业务需求,jwt 只能保证内容不会被篡改。

感谢大家的回复, 如果确实要改成 jwt 的话,看来只能 header+cookie 了。

typescript<br>import { BadRequestException, Injectable } from 'nestjs/common'<br>import { ConfigService } from 'nestjs/config'<br>import { Request } from 'express'<br>import { Strategy } from 'passport-jwt'<br>import { PassportStrategy } from 'nestjs/passport'<br>import { IToken } from '/user/auth/auth.decorator'<br><br>()<br>export class AuthJwtStrategy extends PassportStrategy(Strategy, 'jwt') {<br> constructor(configService: ConfigService) {<br> super({<br> jwtFromRequest: AuthJwtStrategy.fromCookieOrHeader,<br> secretOrKey: configService.get('JWT_SECRET'),<br> })<br> }<br><br> public static fromCookieOrHeader(req: Request): string {<br> const authHeader = req.header('authorization')<br> if (authHeader &amp;&amp; authHeader.startsWith('Bearer ')) {<br> return authHeader.substring(7, authHeader.length)<br> }<br> return req.cookies['access_token']<br> }<br><br> // eslint-disable-next-line class-methods-use-this<br> public async validate(payload: IToken): Promise&lt;IToken&gt; {<br> if (payload.type !== 'access_token') {<br> throw new BadRequestException('token 类型无效')<br> }<br> return payload<br> }<br>}<br>

passport.js 里,passport-jwt 的 strategy 没有粗暴地从 header 取 authorization 字段而是暴露了 jwtFromRequest ,就是希望使用者可以灵活一点。

前端封装 HTTP 请求,如果使用 axios 之类的就更方便了

放那里都行,只要你后端能拿到
但是标准用法是放 header

不放 cookie 里是因为可以省去 csrf 防护

我这边是 cookie 、header 、get 参数顺序检查,同时兼顾 App 、Api 、前端的情况

优先校验 header token ,没有的话看 referrer 为空+GET 则校验 cookie token

接口请求不携带 cookie ,页面 GET 请求会自动携带 cookie

这个需要弄个中间件维持吧

cookie 有安全问题的,你要加 csrf_token 才行。

其实 Cookie 在 SameSite 之后 CSRF 问题好了很多很多了

其实通用的就是登陆成功后把 token 放 cookie 里,大厂里通用的 sso 登陆也是,至于其他安全问题有专门的解决办法,比如 csrf

你说的 session 鉴权其实也是 node 框架把登录状态保存到了 cookie 里,然后服务端解析到之后又放在了 req 对象的 session 字段里方便后端处理。

HTML SSR 和 JWT 匹配不好

JWT 是个有期限且期限内不方便撤销的 secret, 让页面地址包含 JWT 等于把这个 secret 存到用户浏览记录里
不如不用 JWT

JSON Web Token (JWT) is a compact claims representation format
intended for space constrained environments such as HTTP
Authorization headers and URI query parameters.

https://www.rfc-editor.org/rfc/rfc7519

你的问题是如何传输 JWT 的问题,和 JWT 本身没有直接关系。


我请求用的是 axios, 可以这么封装, 登录之后写 setToken, 需要注意的是, setToken 里必须再设置一下 axios.defaults.headers.common[‘Authorization’], 否则登录之后紧接着的其他请求不会带着 token, 没查到为啥, 所以设置一下比较保险, 之后所有的使用 axios 的请求都会带着 token 了.

放 cookie 里

你就当写小程序就完了,小程序咋写 页面咋写,就是给请求多一层封装

按照标准的话,就自己封装请求器自己往头信息加。
其实可以改一下服务端的逻辑,从 cookie 中取出来后再验证,放 cookie 是没问题的,可以利用浏览器机制自动把信息带上去。

月经贴啊,放 cookie 方便,只是怕伪造请求,但是加 https only 限制 domain 的话其实也防住了, 放 header 可以 axios 统一封装,上面的楼也说过了。

jwt 并没限制放哪,既可以放 Authorization 头里,也可以放 cookie 里

axios 请求前拦截把 token 加入到 header 或者直接放到 cookie 中也可以,本身这个用法没有强制约束,只要你前后端协调好就可以

Token 也可以放在 HTTP 的 response 头里,比如用 authorization 头来返回给客户端。
客户端不管是浏览器页面还是 App ,都可以做一个统一的请求拦截器,负责管理 token ,在登陆成功后自动读取返回的 token 信息并存储在本地,拦截每一个发送的请求自动读取本地存储的 token 信息加在 authorization 头里,根据认证策略自动刷新即将过期的 token 。

比如你前端页面使用 axios 发送请求的话,可以看一下 axios 的 interceptors 相关文档。

op 不一定非要走这个 w3c 标准的,只要用了 token 其实就算是 jwt 了。

关于Node.js中使用JWT(JSON Web Token)进行鉴权的问题,这是一个常见的需求,通常用于验证用户的身份和权限。以下是一个基本的示例,展示如何在Node.js中使用JWT进行鉴权。

首先,确保你已经安装了必要的包:

npm install jsonwebtoken express body-parser

然后,你可以创建一个简单的Express服务器,用于生成和验证JWT:

const express = require('express');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');

const app = express();
const PORT = 3000;
const SECRET_KEY = 'your_secret_key';

app.use(bodyParser.json());

// 生成JWT
app.post('/login', (req, res) => {
    const { username, password } = req.body;
    // 这里应该验证用户名和密码
    if (username === 'admin' && password === 'password') {
        const token = jwt.sign({ username }, SECRET_KEY, { expiresIn: '1h' });
        res.json({ token });
    } else {
        res.status(401).send('Invalid Credentials');
    }
});

// 验证JWT
const authenticateJWT = (req, res, next) => {
    const token = req.headers.authorization && req.headers.authorization.split(' ')[1];
    if (token == null) return res.sendStatus(401);
    jwt.verify(token, SECRET_KEY, (err, user) => {
        if (err) return res.sendStatus(403);
        req.user = user;
        next();
    });
};

// 受保护的路由
app.get('/protected', authenticateJWT, (req, res) => {
    res.json({ message: 'This is a protected route', user: req.user });
});

app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

这个示例展示了如何生成JWT以及如何使用中间件来验证JWT。

回到顶部