Angular 5中为受保护路由设置Authorization头部遇授权问题
看起来你搞混了两个关键工具的职责: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
相关产品推荐
相关产品推荐

