\n\n\n`;\nctx.body = template;", "datePublished": "2023-07-11T06:04:01Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/baiheinet", "@type": "Person", "name": "baiheinet"}}, {"text": "直接放在 cookies 注意同源问题就行了。", "interactionStatistic": {"userInteractionCount": 1, "@type": "InteractionCounter", "interactionType": "https://schema.org/LikeAction"}, "datePublished": "2023-07-11T06:05:45Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/victimsss", "@type": "Person", "name": "victimsss"}}, {"text": "jwt 为啥不能放 cookie 里,瞎搞扯,服务端为啥不能同时兼容 Authorization header 和 cookie 传递,这种标准本来就是推荐而已,既然不好用那不是给自己挖坑么", "datePublished": "2023-07-11T06:08:27Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/sujin190", "@type": "Person", "name": "sujin190"}}, {"text": "jwt 当然是放 cookie 里啊....\n/login 验证完在 response 的 header 里加上 Set-Cookie: token=", "interactionStatistic": {"userInteractionCount": 1, "@type": "InteractionCounter", "interactionType": "https://schema.org/LikeAction"}, "datePublished": "2023-07-11T06:10:46Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/NessajCN", "@type": "Person", "name": "NessajCN"}}, {"text": "@sujin190 #7\n确实,怎么传 jwt 是看业务需求,jwt 只能保证内容不会被篡改。", "datePublished": "2023-07-11T06:12:35Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/flyqie", "@type": "Person", "name": "flyqie"}}, {"text": "感谢大家的回复, 如果确实要改成 jwt 的话,看来只能 header+cookie 了。", "datePublished": "2023-07-11T06:14:44Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/cnfczn", "@type": "Person", "name": "cnfczn"}}, {"text": "```typescript\nimport { BadRequestException, Injectable } from '@nestjs/common'\nimport { ConfigService } from '@nestjs/config'\nimport { Request } from 'express'\nimport { Strategy } from 'passport-jwt'\nimport { PassportStrategy } from '@nestjs/passport'\nimport { IToken } from '@/user/auth/auth.decorator'\n@Injectable()\nexport class AuthJwtStrategy extends PassportStrategy(Strategy, 'jwt') {\nconstructor(configService: ConfigService) {\nsuper({\njwtFromRequest: AuthJwtStrategy.fromCookieOrHeader,\nsecretOrKey: configService.get('JWT_SECRET'),\n})\n}\npublic static fromCookieOrHeader(req: Request): string {\nconst authHeader = req.header('authorization')\nif (authHeader && authHeader.startsWith('Bearer ')) {\nreturn authHeader.substring(7, authHeader.length)\n}\nreturn req.cookies['access_token']\n}\n// eslint-disable-next-line class-methods-use-this\npublic async validate(payload: IToken): Promise {\nif (payload.type !== 'access_token') {\nthrow new BadRequestException('token 类型无效')\n}\nreturn payload\n}\n}\n```\npassport.js 里,passport-jwt 的 strategy 没有粗暴地从 header 取 authorization 字段而是暴露了 jwtFromRequest ,就是希望使用者可以灵活一点。", "datePublished": "2023-07-11T06:15:41Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/StrangerA", "@type": "Person", "name": "StrangerA"}}, {"text": "前端封装 HTTP 请求,如果使用 axios 之类的就更方便了", "datePublished": "2023-07-11T06:16:20Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/BreadKiller", "@type": "Person", "name": "BreadKiller"}}, {"text": "放那里都行,只要你后端能拿到\n但是标准用法是放 header", "datePublished": "2023-07-11T06:31:56Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/estk", "@type": "Person", "name": "estk"}}, {"text": "不放 cookie 里是因为可以省去 csrf 防护", "interactionStatistic": {"userInteractionCount": 1, "@type": "InteractionCounter", "interactionType": "https://schema.org/LikeAction"}, "datePublished": "2023-07-11T06:43:31Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/walpurgis", "@type": "Person", "name": "walpurgis"}}, {"text": "我这边是 cookie 、header 、get 参数顺序检查,同时兼顾 App 、Api 、前端的情况", "datePublished": "2023-07-11T06:46:02Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/FrankAdler", "@type": "Person", "name": "FrankAdler"}}, {"text": "优先校验 header token ,没有的话看 referrer 为空+GET 则校验 cookie token\n接口请求不携带 cookie ,页面 GET 请求会自动携带 cookie", "datePublished": "2023-07-11T06:54:10Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/jiangzm", "@type": "Person", "name": "jiangzm"}}, {"text": "这个需要弄个中间件维持吧", "datePublished": "2023-07-11T10:25:22Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/Tyaqing", "@type": "Person", "name": "Tyaqing"}}, {"text": "cookie 有安全问题的,你要加 csrf_token 才行。", "datePublished": "2023-07-11T11:13:00Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/FrankFang128", "@type": "Person", "name": "FrankFang128"}}, {"text": "@walpurgis 其实 Cookie 在 SameSite 之后 CSRF 问题好了很多很多了", "datePublished": "2023-07-11T11:27:14Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/retanoj", "@type": "Person", "name": "retanoj"}}, {"text": "其实通用的就是登陆成功后把 token 放 cookie 里,大厂里通用的 sso 登陆也是,至于其他安全问题有专门的解决办法,比如 csrf", "datePublished": "2023-07-11T11:29:35Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/LawlietZ", "@type": "Person", "name": "LawlietZ"}}, {"text": "你说的 session 鉴权其实也是 node 框架把登录状态保存到了 cookie 里,然后服务端解析到之后又放在了 req 对象的 session 字段里方便后端处理。", "datePublished": "2023-07-11T11:31:04Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/LawlietZ", "@type": "Person", "name": "LawlietZ"}}, {"text": "HTML SSR 和 JWT 匹配不好\nJWT 是个有期限且期限内不方便撤销的 secret, 让页面地址包含 JWT 等于把这个 secret 存到用户浏览记录里\n不如不用 JWT", "datePublished": "2023-07-11T11:38:28Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/momocraft", "@type": "Person", "name": "momocraft"}}, {"text": "JSON Web Token (JWT) is a compact claims representation format\nintended for space constrained environments such as HTTP\nAuthorization headers and URI query parameters.\nhttps://www.rfc-editor.org/rfc/rfc7519\n你的问题是如何传输 JWT 的问题,和 JWT 本身没有直接关系。", "datePublished": "2023-07-11T11:38:58Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/lologame", "@type": "Person", "name": "lologame"}}, {"text": "https://i.imgur.com/MXINr49.png\n我请求用的是 axios, 可以这么封装, 登录之后写 setToken, 需要注意的是, setToken 里必须再设置一下 axios.defaults.headers.common['Authorization'], 否则登录之后紧接着的其他请求不会带着 token, 没查到为啥, 所以设置一下比较保险, 之后所有的使用 axios 的请求都会带着 token 了.", "datePublished": "2023-07-11T11:50:22Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/lonisletend", "@type": "Person", "name": "lonisletend"}}, {"text": "放 cookie 里", "datePublished": "2023-07-11T11:53:22Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/lucifer1108", "@type": "Person", "name": "lucifer1108"}}, {"text": "你就当写小程序就完了,小程序咋写 页面咋写,就是给请求多一层封装", "datePublished": "2023-07-11T11:55:10Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/kingjpa", "@type": "Person", "name": "kingjpa"}}, {"text": "按照标准的话,就自己封装请求器自己往头信息加。\n其实可以改一下服务端的逻辑,从 cookie 中取出来后再验证,放 cookie 是没问题的,可以利用浏览器机制自动把信息带上去。", "datePublished": "2023-07-11T12:00:03Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/keyframes", "@type": "Person", "name": "keyframes"}}, {"text": "月经贴啊,放 cookie 方便,只是怕伪造请求,但是加 https only 限制 domain 的话其实也防住了, 放 header 可以 axios 统一封装,上面的楼也说过了。", "datePublished": "2023-07-11T12:06:35Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/webcape233", "@type": "Person", "name": "webcape233"}}, {"text": "jwt 并没限制放哪,既可以放 Authorization 头里,也可以放 cookie 里", "datePublished": "2023-07-11T13:30:35Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/ysc3839", "@type": "Person", "name": "ysc3839"}}, {"text": "axios 请求前拦截把 token 加入到 header 或者直接放到 cookie 中也可以,本身这个用法没有强制约束,只要你前后端协调好就可以", "datePublished": "2023-07-12T01:31:41Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/layxy", "@type": "Person", "name": "layxy"}}, {"text": "Token 也可以放在 HTTP 的 response 头里,比如用 authorization 头来返回给客户端。\n客户端不管是浏览器页面还是 App ,都可以做一个统一的请求拦截器,负责管理 token ,在登陆成功后自动读取返回的 token 信息并存储在本地,拦截每一个发送的请求自动读取本地存储的 token 信息加在 authorization 头里,根据认证策略自动刷新即将过期的 token 。\n比如你前端页面使用 axios 发送请求的话,可以看一下 axios 的 interceptors 相关文档。", "datePublished": "2023-07-13T09:37:14Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/libook", "@type": "Person", "name": "libook"}}, {"text": "op 不一定非要走这个 w3c 标准的,只要用了 token 其实就算是 jwt 了。", "datePublished": "2023-07-18T04:48:22Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/chuck1in", "@type": "Person", "name": "chuck1in"}}, {"text": "@lonisletend 直接存 local 中 js 能访问,怎么防 xss 攻击呢?还是说你存的是 refresh token ,过一会就过期了?", "datePublished": "2025-09-28T08:44:44Z", "@type": "Comment", "author": {"url": "https://www.v2ex.com/member/user1284", "@type": "Person", "name": "user1284"}}], "interactionStatistic": [{"userInteractionCount": 4879, "@type": "InteractionCounter", "interactionType": "https://schema.org/ViewAction"}, {"userInteractionCount": 9, "@type": "InteractionCounter", "interactionType": "https://schema.org/LikeAction"}, {"userInteractionCount": 33, "@type": "InteractionCounter", "interactionType": "https://schema.org/ReplyAction"}], "text": "之前 nodejs 里习惯用 session 做鉴权,验证通过 req.session 直接保存就可以了。后续不管是浏览器请求还是 ajax 都会拿到 session 。\n现在打算改成 jwt ,看 w3c 标准说是放到 header 的 Authorization 里边,鉴权逻辑已经改好了,但是传递这个头信息有点麻烦。\n例如:\n/login 验证完,json 返回 token ,后续 ajax 请求可以自己加 header ,但是浏览器直接访问的页面并不会主动带 Authorization 信息,直接访问某个 url 例如:/profile 还是未鉴权。\n有没有办法全局修改浏览器在当前网站中的 Authorization 头信息呢?", "datePublished": "2023-07-11T05:52:54Z", "commentCount": 33, "mainEntityOfPage": "https://www.v2ex.com/t/955809", "author": {"url": "https://www.v2ex.com/member/cnfczn", "@type": "Person", "name": "cnfczn"}, "headline": "请教个 jwt 鉴权的问题", "url": "https://www.v2ex.com/t/955809", "isPartOf": {"url": "https://www.v2ex.com/go/nodejs", "@type": "WebPage", "name": "Node.js"}, "@context": "https://schema.org", "@type": "DiscussionForumPosting"}
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cnfczn
V2EX  ›  Node.js

请教个 jwt 鉴权的问题

  •  
  •   cnfczn · 2023 年 7 月 11 日 · 4879 次点击
    这是一个创建于 1009 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    33 条回复    2025-09-28 16:44:44 +08:00
    hsfzxjy
        1
    hsfzxjy  
       2023 年 7 月 11 日 via Android
    jwt 鉴权一般只用于 API 上吧,没有直接访问 API URL 的场景。实在不行 access token 放 cookie 里也能接受
    thinkershare
        2
    thinkershare  
       2023 年 7 月 11 日
    Authorization HEADER 这种授权模式本来就不是为了 Page 模式设计的,它主要是为了服务/服务通讯和 SPA 设计的。
    没有办法全局设置浏览器的 Authorization, 一般如果的确需要使用顶级 GET 请求后端并附带权限,会再 query 字符串上添加 token=JwtToken 。如果你不是当页面,使用 cookie/session 模式才是更方便的。
    LandCruiser
        3
    LandCruiser  
       2023 年 7 月 11 日
    我理解是请求接口才验证 jwt ,请求静态资源不校验 jwt 呀
    dreasky
        4
    dreasky  
       2023 年 7 月 11 日
    封装一个全局请求方法带上 headers 参考 axios 全局拦截器
    baiheinet
        5
    baiheinet  
       2023 年 7 月 11 日
    后端模拟前端登录

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

    ctx.body = template;
    victimsss
        6
    victimsss  
       2023 年 7 月 11 日   ❤️ 1
    直接放在 cookies 注意同源问题就行了。
    sujin190
        7
    sujin190  
       2023 年 7 月 11 日
    jwt 为啥不能放 cookie 里,瞎搞扯,服务端为啥不能同时兼容 Authorization header 和 cookie 传递,这种标准本来就是推荐而已,既然不好用那不是给自己挖坑么
    NessajCN
        8
    NessajCN  
       2023 年 7 月 11 日   ❤️ 1
    jwt 当然是放 cookie 里啊....
    /login 验证完在 response 的 header 里加上 Set-Cookie: token=<jwtstring>
    flyqie
        9
    flyqie  
       2023 年 7 月 11 日
    @sujin190 #7

    确实,怎么传 jwt 是看业务需求,jwt 只能保证内容不会被篡改。
    cnfczn
        10
    cnfczn  
    OP
       2023 年 7 月 11 日
    感谢大家的回复, 如果确实要改成 jwt 的话,看来只能 header+cookie 了。
    StrangerA
        11
    StrangerA  
       2023 年 7 月 11 日
    ```typescript
    import { BadRequestException, Injectable } from '@nestjs/common'
    import { ConfigService } from '@nestjs/config'
    import { Request } from 'express'
    import { Strategy } from 'passport-jwt'
    import { PassportStrategy } from '@nestjs/passport'
    import { IToken } from '@/user/auth/auth.decorator'

    @Injectable()
    export class AuthJwtStrategy extends PassportStrategy(Strategy, 'jwt') {
    constructor(configService: ConfigService) {
    super({
    jwtFromRequest: AuthJwtStrategy.fromCookieOrHeader,
    secretOrKey: configService.get('JWT_SECRET'),
    })
    }

    public static fromCookieOrHeader(req: Request): string {
    const authHeader = req.header('authorization')
    if (authHeader && authHeader.startsWith('Bearer ')) {
    return authHeader.substring(7, authHeader.length)
    }
    return req.cookies['access_token']
    }

    // eslint-disable-next-line class-methods-use-this
    public async validate(payload: IToken): Promise<IToken> {
    if (payload.type !== 'access_token') {
    throw new BadRequestException('token 类型无效')
    }
    return payload
    }
    }
    ```

    passport.js 里,passport-jwt 的 strategy 没有粗暴地从 header 取 authorization 字段而是暴露了 jwtFromRequest ,就是希望使用者可以灵活一点。
    BreadKiller
        12
    BreadKiller  
       2023 年 7 月 11 日
    前端封装 HTTP 请求,如果使用 axios 之类的就更方便了
    estk
        13
    estk  
       2023 年 7 月 11 日
    放那里都行,只要你后端能拿到
    但是标准用法是放 header
    walpurgis
        14
    walpurgis  
       2023 年 7 月 11 日 via iPhone   ❤️ 1
    不放 cookie 里是因为可以省去 csrf 防护
    FrankAdler
        15
    FrankAdler  
       2023 年 7 月 11 日
    我这边是 cookie 、header 、get 参数顺序检查,同时兼顾 App 、Api 、前端的情况
    jiangzm
        16
    jiangzm  
       2023 年 7 月 11 日
    优先校验 header token ,没有的话看 referrer 为空+GET 则校验 cookie token

    接口请求不携带 cookie ,页面 GET 请求会自动携带 cookie
    Tyaqing
        17
    Tyaqing  
       2023 年 7 月 11 日
    这个需要弄个中间件维持吧
    FrankFang128
        18
    FrankFang128  
       2023 年 7 月 11 日
    cookie 有安全问题的,你要加 csrf_token 才行。
    retanoj
        19
    retanoj  
       2023 年 7 月 11 日
    @walpurgis 其实 Cookie 在 SameSite 之后 CSRF 问题好了很多很多了
    LawlietZ
        20
    LawlietZ  
       2023 年 7 月 11 日
    其实通用的就是登陆成功后把 token 放 cookie 里,大厂里通用的 sso 登陆也是,至于其他安全问题有专门的解决办法,比如 csrf
    LawlietZ
        21
    LawlietZ  
       2023 年 7 月 11 日
    你说的 session 鉴权其实也是 node 框架把登录状态保存到了 cookie 里,然后服务端解析到之后又放在了 req 对象的 session 字段里方便后端处理。
    momocraft
        22
    momocraft  
       2023 年 7 月 11 日
    HTML SSR 和 JWT 匹配不好

    JWT 是个有期限且期限内不方便撤销的 secret, 让页面地址包含 JWT 等于把这个 secret 存到用户浏览记录里
    不如不用 JWT
    lologame
        23
    lologame  
       2023 年 7 月 11 日
    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 本身没有直接关系。
    lonisletend
        24
    lonisletend  
       2023 年 7 月 11 日

    我请求用的是 axios, 可以这么封装, 登录之后写 setToken, 需要注意的是, setToken 里必须再设置一下 axios.defaults.headers.common['Authorization'], 否则登录之后紧接着的其他请求不会带着 token, 没查到为啥, 所以设置一下比较保险, 之后所有的使用 axios 的请求都会带着 token 了.
    lucifer1108
        25
    lucifer1108  
       2023 年 7 月 11 日
    放 cookie 里
    kingjpa
        26
    kingjpa  
       2023 年 7 月 11 日
    你就当写小程序就完了,小程序咋写 页面咋写,就是给请求多一层封装
    keyframes
        27
    keyframes  
       2023 年 7 月 11 日
    按照标准的话,就自己封装请求器自己往头信息加。
    其实可以改一下服务端的逻辑,从 cookie 中取出来后再验证,放 cookie 是没问题的,可以利用浏览器机制自动把信息带上去。
    webcape233
        28
    webcape233  
       2023 年 7 月 11 日 via iPhone
    月经贴啊,放 cookie 方便,只是怕伪造请求,但是加 https only 限制 domain 的话其实也防住了, 放 header 可以 axios 统一封装,上面的楼也说过了。
    ysc3839
        29
    ysc3839  
       2023 年 7 月 11 日 via Android
    jwt 并没限制放哪,既可以放 Authorization 头里,也可以放 cookie 里
    layxy
        30
    layxy  
       2023 年 7 月 12 日
    axios 请求前拦截把 token 加入到 header 或者直接放到 cookie 中也可以,本身这个用法没有强制约束,只要你前后端协调好就可以
    libook
        31
    libook  
       2023 年 7 月 13 日
    Token 也可以放在 HTTP 的 response 头里,比如用 authorization 头来返回给客户端。
    客户端不管是浏览器页面还是 App ,都可以做一个统一的请求拦截器,负责管理 token ,在登陆成功后自动读取返回的 token 信息并存储在本地,拦截每一个发送的请求自动读取本地存储的 token 信息加在 authorization 头里,根据认证策略自动刷新即将过期的 token 。

    比如你前端页面使用 axios 发送请求的话,可以看一下 axios 的 interceptors 相关文档。
    chuck1in
        32
    chuck1in  
       2023 年 7 月 18 日
    op 不一定非要走这个 w3c 标准的,只要用了 token 其实就算是 jwt 了。
    user1284
        33
    user1284  
       2025 年 9 月 28 日
    @lonisletend 直接存 local 中 js 能访问,怎么防 xss 攻击呢?还是说你存的是 refresh token ,过一会就过期了?
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   5426 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 238ms · UTC 07:14 · PVG 15:14 · LAX 00:14 · JFK 03:14
    ♥ Do have faith in what you're doing.