You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 5中为受保护路由设置Authorization头部遇授权问题

解决Angular路由保护与JWT验证的Unauthorized问题

看起来你搞混了两个关键工具的职责:AuthInterceptor 只负责给HTTP请求自动添加Authorization头,而直接访问路由时,你需要用Angular路由守卫来控制用户是否有权限进入该路由。咱们一步步排查并解决这个问题:

核心问题拆解

当你直接访问/user/profile时,Angular会直接尝试加载ProfileComponent——如果用户未登录(localStorage无有效token),组件初始化时发起的/profile接口请求会被后端passport-jwt拒绝;而你真正需要的是:未登录用户根本不能进入这个路由,已登录用户进入后,接口请求能自动带上有效token。


步骤1:添加Angular路由守卫(CanActivate)

这是控制路由访问权限的核心,它会在路由激活前检查用户登录状态。

1.1 创建AuthGuard服务

import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    const token = localStorage.getItem('token');
    if (token) {
      // 简单验证token有效性(可进一步解析检查过期时间)
      try {
        // 拆分Bearer前缀,解析JWT payload
        const payload = JSON.parse(atob(token.split(' ')[1]));
        const expDate = new Date(payload.exp * 1000);
        if (expDate > new Date()) {
          return true; // token有效,允许进入路由
        }
      } catch (err) {
        // 解析失败,清除无效token
        localStorage.removeItem('token');
        localStorage.removeItem('userId');
      }
    }
    // 无有效token,跳转到登录页并记录当前路由
    this.router.navigate(['/signin'], { queryParams: { returnUrl: state.url } });
    return false;
  }
}

1.2 在路由配置中启用守卫

修改AppRoutingModule,给/user/profile路由添加守卫:

import { AuthGuard } from './auth.guard';

const routes: Routes = [
  // 其他路由配置...
  { 
    path: 'user/profile', 
    component: ProfileComponent,
    canActivate: [AuthGuard] // 启用路由守卫
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

步骤2:优化AuthInterceptor逻辑

你的拦截器基本没问题,可优化细节避免重复操作:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = localStorage.getItem('token');
    if (token) {
      // 克隆请求并添加Authorization头(后端返回的token已带Bearer前缀,直接使用即可)
      const authReq = req.clone({
        headers: req.headers.set('Authorization', token)
      });
      return next.handle(authReq);
    }
    return next.handle(req);
  }
}

步骤3:验证后端passport-jwt配置

确保你的JWT策略正确解析Bearer格式的token:

const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const keys = require('../config/keys');
const User = require('../models/User');

const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); // 自动提取Bearer token
opts.secretOrKey = keys.secretOrKey;

module.exports = passport => {
  passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
    User.findById(jwt_payload.id)
      .then(user => user ? done(null, user) : done(null, false))
      .catch(err => console.error(err));
  }));
};

步骤4:检查ProfileComponent的接口调用

确保组件初始化时正确发起请求:

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-profile',
  templateUrl: './profile.component.html'
})
export class ProfileComponent implements OnInit {
  userProfile: any;

  constructor(private http: HttpClient) { }

  ngOnInit(): void {
    // 发起请求时,AuthInterceptor会自动添加Authorization头
    this.http.get('http://localhost:3000/user/profile')
      .subscribe(
        data => this.userProfile = data,
        error => console.error('获取用户信息失败:', error)
      );
  }
}

最终效果

  • 未登录用户直接访问/user/profile会被路由守卫跳转到登录页
  • 已登录用户访问路由时,守卫验证token有效后允许进入,组件发起的请求会自动带上Authorization头,后端验证通过后返回用户信息

内容的提问来源于stack exchange,提问作者The_Wolf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:29:26