[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fjwt":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fjwt":1224,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fjwt":1243},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":13,"pinned":14,"draft":14,"body":15,"seo":1220,"stem":1221,"id":1222,"extension":1223},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fjwt","JWT 与 Passport 授权","","技能小册",[12],"nestjs","2021-08-10",false,{"type":16,"value":17,"toc":1212},"minimark",[18,22,39,59,63,110,114,121,348,359,568,572,893,909,913,929,936,940,1149,1152,1208],[19,20,8],"h1",{"id":21},"jwt-与-passport-授权",[23,24,25],"blockquote",{},[26,27,28,32,33,38],"p",{},[29,30,31],"strong",{},"归档","：完整、可维护的写法见 ",[34,35,37],"a",{"href":36},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fnew\u002Fauth","new\u002Fauth","。下文为早期项目中的 JWT + Redis 校验片段。",[26,40,41,42,45,46,50,51,54,55,58],{},"身份验证常见流程：客户端用用户名密码登录 → 服务端签发 ",[29,43,44],{},"JWT"," → 后续请求在 ",[47,48,49],"code",{},"Authorization: Bearer \u003Ctoken>"," 中携带 → ",[29,52,53],{},"Guard"," 校验并挂载 ",[47,56,57],{},"request.user","。",[60,61,62],"h2",{"id":62},"安装依赖",[64,65,69],"pre",{"className":66,"code":67,"language":68,"meta":9,"style":9},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","pnpm add @nestjs\u002Fjwt @nestjs\u002Fpassport passport passport-jwt\npnpm add -D @types\u002Fpassport-jwt\n","bash",[47,70,71,96],{"__ignoreMap":9},[72,73,76,80,84,87,90,93],"span",{"class":74,"line":75},"line",1,[72,77,79],{"class":78},"sbgvK","pnpm",[72,81,83],{"class":82},"s_sjI"," add",[72,85,86],{"class":82}," @nestjs\u002Fjwt",[72,88,89],{"class":82}," @nestjs\u002Fpassport",[72,91,92],{"class":82}," passport",[72,94,95],{"class":82}," passport-jwt\n",[72,97,99,101,103,107],{"class":74,"line":98},2,[72,100,79],{"class":78},[72,102,83],{"class":82},[72,104,106],{"class":105},"stzsN"," -D",[72,108,109],{"class":82}," @types\u002Fpassport-jwt\n",[60,111,113],{"id":112},"注册-jwtmodule","注册 JwtModule",[26,115,116,117,120],{},"在 ",[47,118,119],{},"AuthModule","（或根模块）中注册：",[64,122,126],{"className":123,"code":124,"language":125,"meta":9,"style":9},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","import { Module } from \"@nestjs\u002Fcommon\";\nimport { JwtModule } from \"@nestjs\u002Fjwt\";\n\n@Module({\n  imports: [\n    JwtModule.register({\n      global: true,\n      secret: process.env.JWT_SECRET, \u002F\u002F 生产环境勿硬编码\n      signOptions: { expiresIn: \"1h\" },\n    }),\n  ],\n})\nexport class AuthModule {}\n","ts",[47,127,128,161,183,190,206,219,235,250,279,304,315,323,332],{"__ignoreMap":9},[72,129,130,134,138,142,145,148,152,155,158],{"class":74,"line":75},[72,131,133],{"class":132},"sVHd0","import",[72,135,137],{"class":136},"sP7_E"," {",[72,139,141],{"class":140},"su5hD"," Module",[72,143,144],{"class":136}," }",[72,146,147],{"class":132}," from",[72,149,151],{"class":150},"sjJ54"," \"",[72,153,154],{"class":82},"@nestjs\u002Fcommon",[72,156,157],{"class":150},"\"",[72,159,160],{"class":136},";\n",[72,162,163,165,167,170,172,174,176,179,181],{"class":74,"line":98},[72,164,133],{"class":132},[72,166,137],{"class":136},[72,168,169],{"class":140}," JwtModule",[72,171,144],{"class":136},[72,173,147],{"class":132},[72,175,151],{"class":150},[72,177,178],{"class":82},"@nestjs\u002Fjwt",[72,180,157],{"class":150},[72,182,160],{"class":136},[72,184,186],{"class":74,"line":185},3,[72,187,189],{"emptyLinePlaceholder":188},true,"\n",[72,191,193,196,200,203],{"class":74,"line":192},4,[72,194,195],{"class":136},"@",[72,197,199],{"class":198},"sGLFI","Module",[72,201,202],{"class":140},"(",[72,204,205],{"class":136},"{\n",[72,207,209,213,216],{"class":74,"line":208},5,[72,210,212],{"class":211},"skxfh","  imports",[72,214,215],{"class":136},":",[72,217,218],{"class":140}," [\n",[72,220,222,225,228,231,233],{"class":74,"line":221},6,[72,223,224],{"class":140},"    JwtModule",[72,226,227],{"class":136},".",[72,229,230],{"class":198},"register",[72,232,202],{"class":140},[72,234,205],{"class":136},[72,236,238,241,243,247],{"class":74,"line":237},7,[72,239,240],{"class":211},"      global",[72,242,215],{"class":136},[72,244,246],{"class":245},"syTEX"," true",[72,248,249],{"class":136},",\n",[72,251,253,256,258,261,263,266,268,272,275],{"class":74,"line":252},8,[72,254,255],{"class":211},"      secret",[72,257,215],{"class":136},[72,259,260],{"class":140}," process",[72,262,227],{"class":136},[72,264,265],{"class":140},"env",[72,267,227],{"class":136},[72,269,271],{"class":270},"s_hVV","JWT_SECRET",[72,273,274],{"class":136},",",[72,276,278],{"class":277},"sutJx"," \u002F\u002F 生产环境勿硬编码\n",[72,280,282,285,287,289,292,294,296,299,301],{"class":74,"line":281},9,[72,283,284],{"class":211},"      signOptions",[72,286,215],{"class":136},[72,288,137],{"class":136},[72,290,291],{"class":211}," expiresIn",[72,293,215],{"class":136},[72,295,151],{"class":150},[72,297,298],{"class":82},"1h",[72,300,157],{"class":150},[72,302,303],{"class":136}," },\n",[72,305,307,310,313],{"class":74,"line":306},10,[72,308,309],{"class":136},"    }",[72,311,312],{"class":140},")",[72,314,249],{"class":136},[72,316,318,321],{"class":74,"line":317},11,[72,319,320],{"class":140},"  ]",[72,322,249],{"class":136},[72,324,326,329],{"class":74,"line":325},12,[72,327,328],{"class":136},"}",[72,330,331],{"class":140},")\n",[72,333,335,338,342,345],{"class":74,"line":334},13,[72,336,337],{"class":132},"export",[72,339,341],{"class":340},"sbsja"," class",[72,343,344],{"class":78}," AuthModule",[72,346,347],{"class":136}," {}\n",[26,349,350,351,354,355,358],{},"使用 ",[47,352,353],{},"@nestjs\u002Fconfig"," 时推荐 ",[47,356,357],{},"registerAsync","：",[64,360,362],{"className":123,"code":361,"language":125,"meta":9,"style":9},"import { ConfigModule, ConfigService } from \"@nestjs\u002Fconfig\";\n\nJwtModule.registerAsync({\n  imports: [ConfigModule],\n  useFactory: (config: ConfigService) => ({\n    secret: config.getOrThrow\u003Cstring>(\"JWT_SECRET\"),\n    signOptions: {\n      expiresIn: config.get\u003Cstring>(\"JWT_EXPIRES_IN\", \"1h\"),\n    },\n  }),\n  inject: [ConfigService],\n}),\n",[47,363,364,390,394,407,418,446,483,493,534,539,548,560],{"__ignoreMap":9},[72,365,366,368,370,373,375,378,380,382,384,386,388],{"class":74,"line":75},[72,367,133],{"class":132},[72,369,137],{"class":136},[72,371,372],{"class":140}," ConfigModule",[72,374,274],{"class":136},[72,376,377],{"class":140}," ConfigService",[72,379,144],{"class":136},[72,381,147],{"class":132},[72,383,151],{"class":150},[72,385,353],{"class":82},[72,387,157],{"class":150},[72,389,160],{"class":136},[72,391,392],{"class":74,"line":98},[72,393,189],{"emptyLinePlaceholder":188},[72,395,396,399,401,403,405],{"class":74,"line":185},[72,397,398],{"class":140},"JwtModule",[72,400,227],{"class":136},[72,402,357],{"class":198},[72,404,202],{"class":140},[72,406,205],{"class":136},[72,408,409,411,413,416],{"class":74,"line":192},[72,410,212],{"class":211},[72,412,215],{"class":136},[72,414,415],{"class":140}," [ConfigModule]",[72,417,249],{"class":136},[72,419,420,423,425,428,432,435,437,439,442,444],{"class":74,"line":208},[72,421,422],{"class":198},"  useFactory",[72,424,215],{"class":136},[72,426,427],{"class":136}," (",[72,429,431],{"class":430},"s99_P","config",[72,433,215],{"class":434},"smGrS",[72,436,377],{"class":78},[72,438,312],{"class":136},[72,440,441],{"class":340}," =>",[72,443,427],{"class":140},[72,445,205],{"class":136},[72,447,448,451,453,456,458,461,464,468,471,473,475,477,479,481],{"class":74,"line":221},[72,449,450],{"class":211},"    secret",[72,452,215],{"class":136},[72,454,455],{"class":140}," config",[72,457,227],{"class":136},[72,459,460],{"class":198},"getOrThrow",[72,462,463],{"class":136},"\u003C",[72,465,467],{"class":466},"sZMiF","string",[72,469,470],{"class":136},">",[72,472,202],{"class":140},[72,474,157],{"class":150},[72,476,271],{"class":82},[72,478,157],{"class":150},[72,480,312],{"class":140},[72,482,249],{"class":136},[72,484,485,488,490],{"class":74,"line":237},[72,486,487],{"class":211},"    signOptions",[72,489,215],{"class":136},[72,491,492],{"class":136}," {\n",[72,494,495,498,500,502,504,507,509,511,513,515,517,520,522,524,526,528,530,532],{"class":74,"line":252},[72,496,497],{"class":211},"      expiresIn",[72,499,215],{"class":136},[72,501,455],{"class":140},[72,503,227],{"class":136},[72,505,506],{"class":198},"get",[72,508,463],{"class":136},[72,510,467],{"class":466},[72,512,470],{"class":136},[72,514,202],{"class":140},[72,516,157],{"class":150},[72,518,519],{"class":82},"JWT_EXPIRES_IN",[72,521,157],{"class":150},[72,523,274],{"class":136},[72,525,151],{"class":150},[72,527,298],{"class":82},[72,529,157],{"class":150},[72,531,312],{"class":140},[72,533,249],{"class":136},[72,535,536],{"class":74,"line":281},[72,537,538],{"class":136},"    },\n",[72,540,541,544,546],{"class":74,"line":306},[72,542,543],{"class":136},"  }",[72,545,312],{"class":140},[72,547,249],{"class":136},[72,549,550,553,555,558],{"class":74,"line":317},[72,551,552],{"class":211},"  inject",[72,554,215],{"class":136},[72,556,557],{"class":140}," [ConfigService]",[72,559,249],{"class":136},[72,561,562,564,566],{"class":74,"line":325},[72,563,328],{"class":136},[72,565,312],{"class":140},[72,567,249],{"class":136},[60,569,571],{"id":570},"passport-jwt-策略","Passport JWT 策略",[64,573,575],{"className":123,"code":574,"language":125,"meta":9,"style":9},"import { ExtractJwt, Strategy } from \"passport-jwt\";\nimport { PassportStrategy } from \"@nestjs\u002Fpassport\";\nimport { Injectable } from \"@nestjs\u002Fcommon\";\n\nexport interface JwtPayload {\n  sub: string;\n  username: string;\n}\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: process.env.JWT_SECRET,\n    });\n  }\n\n  async validate(payload: JwtPayload) {\n    \u002F\u002F 返回的对象会挂载到 request.user\n    return { userId: payload.sub, username: payload.username };\n  }\n}\n",[47,576,577,604,626,647,651,663,676,687,692,696,706,725,735,744,763,776,796,805,811,816,839,845,883,888],{"__ignoreMap":9},[72,578,579,581,583,586,588,591,593,595,597,600,602],{"class":74,"line":75},[72,580,133],{"class":132},[72,582,137],{"class":136},[72,584,585],{"class":140}," ExtractJwt",[72,587,274],{"class":136},[72,589,590],{"class":140}," Strategy",[72,592,144],{"class":136},[72,594,147],{"class":132},[72,596,151],{"class":150},[72,598,599],{"class":82},"passport-jwt",[72,601,157],{"class":150},[72,603,160],{"class":136},[72,605,606,608,610,613,615,617,619,622,624],{"class":74,"line":98},[72,607,133],{"class":132},[72,609,137],{"class":136},[72,611,612],{"class":140}," PassportStrategy",[72,614,144],{"class":136},[72,616,147],{"class":132},[72,618,151],{"class":150},[72,620,621],{"class":82},"@nestjs\u002Fpassport",[72,623,157],{"class":150},[72,625,160],{"class":136},[72,627,628,630,632,635,637,639,641,643,645],{"class":74,"line":185},[72,629,133],{"class":132},[72,631,137],{"class":136},[72,633,634],{"class":140}," Injectable",[72,636,144],{"class":136},[72,638,147],{"class":132},[72,640,151],{"class":150},[72,642,154],{"class":82},[72,644,157],{"class":150},[72,646,160],{"class":136},[72,648,649],{"class":74,"line":192},[72,650,189],{"emptyLinePlaceholder":188},[72,652,653,655,658,661],{"class":74,"line":208},[72,654,337],{"class":132},[72,656,657],{"class":340}," interface",[72,659,660],{"class":78}," JwtPayload",[72,662,492],{"class":136},[72,664,665,669,671,674],{"class":74,"line":221},[72,666,668],{"class":667},"sucvu","  sub",[72,670,215],{"class":434},[72,672,673],{"class":466}," string",[72,675,160],{"class":136},[72,677,678,681,683,685],{"class":74,"line":237},[72,679,680],{"class":667},"  username",[72,682,215],{"class":434},[72,684,673],{"class":466},[72,686,160],{"class":136},[72,688,689],{"class":74,"line":252},[72,690,691],{"class":136},"}\n",[72,693,694],{"class":74,"line":281},[72,695,189],{"emptyLinePlaceholder":188},[72,697,698,700,703],{"class":74,"line":306},[72,699,195],{"class":136},[72,701,702],{"class":198},"Injectable",[72,704,705],{"class":140},"()\n",[72,707,708,710,712,715,718,720,723],{"class":74,"line":317},[72,709,337],{"class":132},[72,711,341],{"class":340},[72,713,714],{"class":78}," JwtStrategy",[72,716,717],{"class":340}," extends",[72,719,612],{"class":198},[72,721,722],{"class":140},"(Strategy) ",[72,724,205],{"class":136},[72,726,727,730,733],{"class":74,"line":325},[72,728,729],{"class":340},"  constructor",[72,731,732],{"class":136},"()",[72,734,492],{"class":136},[72,736,737,740,742],{"class":74,"line":334},[72,738,739],{"class":270},"    super",[72,741,202],{"class":211},[72,743,205],{"class":136},[72,745,747,750,752,754,756,759,761],{"class":74,"line":746},14,[72,748,749],{"class":211},"      jwtFromRequest",[72,751,215],{"class":136},[72,753,585],{"class":140},[72,755,227],{"class":136},[72,757,758],{"class":198},"fromAuthHeaderAsBearerToken",[72,760,732],{"class":211},[72,762,249],{"class":136},[72,764,766,769,771,774],{"class":74,"line":765},15,[72,767,768],{"class":211},"      ignoreExpiration",[72,770,215],{"class":136},[72,772,773],{"class":245}," false",[72,775,249],{"class":136},[72,777,779,782,784,786,788,790,792,794],{"class":74,"line":778},16,[72,780,781],{"class":211},"      secretOrKey",[72,783,215],{"class":136},[72,785,260],{"class":140},[72,787,227],{"class":136},[72,789,265],{"class":140},[72,791,227],{"class":136},[72,793,271],{"class":270},[72,795,249],{"class":136},[72,797,799,801,803],{"class":74,"line":798},17,[72,800,309],{"class":136},[72,802,312],{"class":211},[72,804,160],{"class":136},[72,806,808],{"class":74,"line":807},18,[72,809,810],{"class":136},"  }\n",[72,812,814],{"class":74,"line":813},19,[72,815,189],{"emptyLinePlaceholder":188},[72,817,819,822,826,828,831,833,835,837],{"class":74,"line":818},20,[72,820,821],{"class":340},"  async",[72,823,825],{"class":824},"sVXei"," validate",[72,827,202],{"class":136},[72,829,830],{"class":430},"payload",[72,832,215],{"class":434},[72,834,660],{"class":78},[72,836,312],{"class":136},[72,838,492],{"class":136},[72,840,842],{"class":74,"line":841},21,[72,843,844],{"class":277},"    \u002F\u002F 返回的对象会挂载到 request.user\n",[72,846,848,851,853,856,858,861,863,866,868,871,873,875,877,880],{"class":74,"line":847},22,[72,849,850],{"class":132},"    return",[72,852,137],{"class":136},[72,854,855],{"class":211}," userId",[72,857,215],{"class":136},[72,859,860],{"class":140}," payload",[72,862,227],{"class":136},[72,864,865],{"class":140},"sub",[72,867,274],{"class":136},[72,869,870],{"class":211}," username",[72,872,215],{"class":136},[72,874,860],{"class":140},[72,876,227],{"class":136},[72,878,879],{"class":140},"username",[72,881,882],{"class":136}," };\n",[72,884,886],{"class":74,"line":885},23,[72,887,810],{"class":136},[72,889,891],{"class":74,"line":890},24,[72,892,691],{"class":136},[26,894,116,895,897,898,901,902,905,906,58],{},[47,896,119],{}," 的 ",[47,899,900],{},"providers"," 中注册 ",[47,903,904],{},"JwtStrategy","，并 ",[47,907,908],{},"imports: [PassportModule.register({ defaultStrategy: \"jwt\" })]",[60,910,912],{"id":911},"全局守卫与-public","全局守卫与 @Public()",[26,914,915,916,920,921,924,925,928],{},"结合 ",[34,917,919],{"href":918},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fnext","路由守卫"," 中的 ",[47,922,923],{},"JwtAuthGuard"," 与 ",[47,926,927],{},"@Public()"," 装饰器，可对大部分路由默认鉴权、对登录\u002F注册等接口放行。",[26,930,931,932,935],{},"若需在服务端使 token 失效（登出、踢人），可将签发后的 token 存入 Redis，在 ",[47,933,934],{},"validate"," 中与请求头中的 token 比对（见下方历史片段）。",[60,937,939],{"id":938},"可选redis-校验-token历史片段","可选：Redis 校验 token（历史片段）",[64,941,943],{"className":123,"code":942,"language":125,"meta":9,"style":9},"async validateToken(payload: JwtPayload, requestToken: string) {\n  const cached = await this.cacheService.get(`${REDIS_TOKEN_KEY}${payload.sub}`);\n  if (requestToken !== cached) {\n    throw new UnauthorizedException(\"登录状态已过期\");\n  }\n  const userJson = await this.cacheService.get(`${REDIS_USER_INFO_KEY}${payload.sub}`);\n  return userJson ? JSON.parse(userJson) : { userId: payload.sub };\n}\n",[47,944,945,963,1014,1034,1058,1062,1104,1145],{"__ignoreMap":9},[72,946,947,950,953,956,958,961],{"class":74,"line":75},[72,948,949],{"class":140},"async ",[72,951,952],{"class":198},"validateToken",[72,954,955],{"class":140},"(payload: JwtPayload",[72,957,274],{"class":136},[72,959,960],{"class":140}," requestToken: string) ",[72,962,205],{"class":136},[72,964,965,968,971,974,977,981,983,986,988,990,992,995,998,1001,1003,1005,1007,1010,1012],{"class":74,"line":98},[72,966,967],{"class":340},"  const",[72,969,970],{"class":270}," cached",[72,972,973],{"class":434}," =",[72,975,976],{"class":132}," await",[72,978,980],{"class":979},"s39Yj"," this",[72,982,227],{"class":136},[72,984,985],{"class":140},"cacheService",[72,987,227],{"class":136},[72,989,506],{"class":198},[72,991,202],{"class":211},[72,993,994],{"class":150},"`${",[72,996,997],{"class":270},"REDIS_TOKEN_KEY",[72,999,1000],{"class":150},"}${",[72,1002,830],{"class":140},[72,1004,227],{"class":150},[72,1006,865],{"class":140},[72,1008,1009],{"class":150},"}`",[72,1011,312],{"class":211},[72,1013,160],{"class":136},[72,1015,1016,1019,1021,1024,1027,1029,1032],{"class":74,"line":185},[72,1017,1018],{"class":132},"  if",[72,1020,427],{"class":211},[72,1022,1023],{"class":140},"requestToken",[72,1025,1026],{"class":434}," !==",[72,1028,970],{"class":140},[72,1030,1031],{"class":211},") ",[72,1033,205],{"class":136},[72,1035,1036,1039,1042,1045,1047,1049,1052,1054,1056],{"class":74,"line":192},[72,1037,1038],{"class":132},"    throw",[72,1040,1041],{"class":434}," new",[72,1043,1044],{"class":198}," UnauthorizedException",[72,1046,202],{"class":211},[72,1048,157],{"class":150},[72,1050,1051],{"class":82},"登录状态已过期",[72,1053,157],{"class":150},[72,1055,312],{"class":211},[72,1057,160],{"class":136},[72,1059,1060],{"class":74,"line":208},[72,1061,810],{"class":136},[72,1063,1064,1066,1069,1071,1073,1075,1077,1079,1081,1083,1085,1087,1090,1092,1094,1096,1098,1100,1102],{"class":74,"line":221},[72,1065,967],{"class":340},[72,1067,1068],{"class":270}," userJson",[72,1070,973],{"class":434},[72,1072,976],{"class":132},[72,1074,980],{"class":979},[72,1076,227],{"class":136},[72,1078,985],{"class":140},[72,1080,227],{"class":136},[72,1082,506],{"class":198},[72,1084,202],{"class":211},[72,1086,994],{"class":150},[72,1088,1089],{"class":270},"REDIS_USER_INFO_KEY",[72,1091,1000],{"class":150},[72,1093,830],{"class":140},[72,1095,227],{"class":150},[72,1097,865],{"class":140},[72,1099,1009],{"class":150},[72,1101,312],{"class":211},[72,1103,160],{"class":136},[72,1105,1106,1109,1111,1114,1117,1119,1122,1124,1127,1129,1131,1133,1135,1137,1139,1141,1143],{"class":74,"line":237},[72,1107,1108],{"class":132},"  return",[72,1110,1068],{"class":140},[72,1112,1113],{"class":434}," ?",[72,1115,1116],{"class":270}," JSON",[72,1118,227],{"class":136},[72,1120,1121],{"class":198},"parse",[72,1123,202],{"class":211},[72,1125,1126],{"class":140},"userJson",[72,1128,1031],{"class":211},[72,1130,215],{"class":434},[72,1132,137],{"class":136},[72,1134,855],{"class":211},[72,1136,215],{"class":136},[72,1138,860],{"class":140},[72,1140,227],{"class":136},[72,1142,865],{"class":140},[72,1144,882],{"class":136},[72,1146,1147],{"class":74,"line":252},[72,1148,691],{"class":136},[60,1150,1151],{"id":1151},"参考文献",[1153,1154,1155,1168],"table",{},[1156,1157,1158],"thead",{},[1159,1160,1161,1165],"tr",{},[1162,1163,1164],"th",{},"资料",[1162,1166,1167],{},"说明",[1169,1170,1171,1185,1197],"tbody",{},[1159,1172,1173,1182],{},[1174,1175,1176],"td",{},[34,1177,1181],{"href":1178,"rel":1179},"https:\u002F\u002Fdocs.nestjs.com\u002Fsecurity\u002Fauthentication",[1180],"nofollow","Authentication",[1174,1183,1184],{},"Nest 官方认证",[1159,1186,1187,1193],{},[1174,1188,1189],{},[34,1190,44],{"href":1191,"rel":1192},"https:\u002F\u002Fdocs.nestjs.com\u002Fsecurity\u002Fauthentication#jwt-functionality",[1180],[1174,1194,1195],{},[47,1196,178],{},[1159,1198,1199,1205],{},[1174,1200,1201],{},[34,1202,599],{"href":1203,"rel":1204},"https:\u002F\u002Fgithub.com\u002Fmikenicholson\u002Fpassport-jwt",[1180],[1174,1206,1207],{},"策略实现",[1209,1210,1211],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sucvu, html code.shiki .sucvu{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":9,"searchDepth":98,"depth":98,"links":1213},[1214,1215,1216,1217,1218,1219],{"id":62,"depth":98,"text":62},{"id":112,"depth":98,"text":113},{"id":570,"depth":98,"text":571},{"id":911,"depth":98,"text":912},{"id":938,"depth":98,"text":939},{"id":1151,"depth":98,"text":1151},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fend\u002FNestJS\u002Fbefore\u002Fjwt授权","knowledge\u002Fknowledge\u002Fbooklet\u002Fend\u002FNestJS\u002Fbefore\u002Fjwt授权.md","md",{"items":1225},[1226,1229,1232,1235,1239,1242],{"path":1227,"title":1228,"description":9,"category":10,"score":221},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fexce","异常处理器",{"path":1230,"title":1231,"description":9,"category":10,"score":221},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fenv","环境加载",{"path":1233,"title":1234,"description":9,"category":10,"score":221},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fdatabase","数据库的配置",{"path":1236,"title":1237,"description":1238,"category":10,"score":221},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Finfo","归档说明（before\u002F）","本目录（before\u002F）为早期 NestJS 实战笔记：以完整业务片段（守卫、拦截器、MongoDB、JWT 等）为主，写法与文件命名不统一。新项目请跟 new\u002F 主线，技术细节以 docs.nestjs.com 为准。",{"path":1240,"title":1241,"description":9,"category":10,"score":221},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fitc","统一响应格式拦截器",{"path":918,"title":919,"description":9,"category":10,"score":221},{"series":1244,"title":1245,"items":1246,"index":237,"prev":1276,"next":1277},"booklet\u002Fend\u002Fnestjs\u002Fbefore","before",[1247,1249,1253,1255,1257,1259,1263,1265,1266,1270,1272],{"path":1233,"title":1234,"date":1248,"pinned":14},"2024-06-22",{"path":1250,"title":1251,"date":1252,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fdemo","入手Demo","2022-10-15",{"path":1230,"title":1231,"date":1254,"pinned":14},"2024-09-01",{"path":1227,"title":1228,"date":1256,"pinned":14},"2026-03-17",{"path":1236,"title":1237,"date":1258,"pinned":14},"2023-08-31",{"path":1260,"title":1261,"date":1262,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Finjectable","操作日志拦截器","2020-02-20",{"path":1240,"title":1241,"date":1264,"pinned":14},"2023-08-17",{"path":7,"title":8,"date":13,"pinned":14},{"path":1267,"title":1268,"date":1269,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fmi","Nest 中间件","2022-06-21",{"path":918,"title":919,"date":1271,"pinned":14},"2022-12-01",{"path":1273,"title":1274,"date":1275,"pinned":14},"\u002Fknowledge\u002Fbooklet\u002Fend\u002Fnestjs\u002Fbefore\u002Fother","其他配置","2022-05-23",{"path":1240,"title":1241,"date":1264,"pinned":14},{"path":1267,"title":1268,"date":1269,"pinned":14}]