基于MEAN栈的Passport鉴权401未授权场景处理咨询
看来你遇到了JWT令牌失效后,前端只在控制台打印"Unauthorized"但没自动处理跳转的问题。其实这个需求需要后端+前端配合来实现,我帮你一步步梳理:
第一步:先让后端返回明确的401错误状态码
你的passport.js里已经配置了JWT策略,但现在鉴权失败时,Passport默认的响应可能没有明确返回401状态码,导致前端没法准确判断。咱们需要做两处调整:
1. 给受保护路由添加鉴权中间件
在你的各个路由文件(比如users.js、customer.js)里,所有需要登录才能访问的接口,都要加上passport.authenticate('jwt', {session: false})中间件,并且处理鉴权失败的情况:
// 举个例子:用户信息接口 router.get('/profile', passport.authenticate('jwt', {session: false}), (req, res) => { // 正常返回用户数据 res.json({user: req.user}); }, (err, req, res, next) => { // 捕获Passport的未授权错误 if (err.name === 'UnauthorizedError') { res.status(401).json({success: false, message: 'Token已失效,请重新登录'}); } } );
2. 全局错误处理(可选但推荐)
如果不想每个路由都写错误处理,你可以在app.js里加一个全局错误中间件,统一处理所有鉴权失败的情况:
// 放在所有路由注册之后 app.use((err, req, res, next) => { if (err.name === 'UnauthorizedError') { res.status(401).json({success: false, message: 'Token失效或未授权'}); } else { // 其他错误交给默认处理 next(err); } });
这样后端在Token失效或无效时,就会明确返回401状态码,前端就能准确捕获这个错误了。
第二步:前端用HTTP拦截器处理401错误(Angular端)
因为是MEAN栈,前端是Angular,咱们可以创建一个HTTP拦截器,拦截所有接口响应,一旦检测到401,就执行清除localStorage和跳转登录页的逻辑。
1. 创建鉴权拦截器
新建一个auth.interceptor.ts文件:
import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { Router } from '@angular/router'; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private router: Router) {} intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { return next.handle(request).pipe( catchError((error: HttpErrorResponse) => { // 检测到401未授权状态码 if (error.status === 401) { // 清除localStorage里的Token和用户信息 localStorage.removeItem('token'); localStorage.removeItem('user'); // 跳转到登录页面 this.router.navigate(['/login']); } // 把错误继续抛出,方便其他组件处理(可选) return throwError(() => new Error(error.message || '服务器异常')); }) ); } }
2. 注册拦截器
在app.module.ts里把这个拦截器注册到Angular的HTTP服务中:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { AuthInterceptor } from './auth.interceptor'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, AppRoutingModule, HttpClientModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true // 允许多个拦截器 } ], bootstrap: [AppComponent] }) export class AppModule { }
额外提醒(如果是AngularJS老版本)
要是你的前端用的是AngularJS(1.x版本),拦截器写法不一样,用$httpProvider来注册:
angular.module('yourApp') .factory('authInterceptor', function($q, $location, $window) { return { responseError: function(rejection) { if (rejection.status === 401) { $window.localStorage.removeItem('token'); $location.path('/login'); } return $q.reject(rejection); } }; }); // 在配置阶段添加拦截器 angular.module('yourApp') .config(function($httpProvider) { $httpProvider.interceptors.push('authInterceptor'); });
最后别忘了,前端发送请求时要把Token放在请求头里,比如Authorization: jwt <你的token>,这样后端Passport才能正确提取验证。
这样设置后,下次Token失效时,用户点击任何需要鉴权的链接,前端都会自动清除缓存并跳转到登录页,而不是只在控制台打印提示啦!
内容的提问来源于stack exchange,提问作者Sithys

