Angular 7中JWT授权路由跳转异常及Token刷新问题求助
Angular 7 JWT登录后路由跳转被拦截?问题出在这!
兄弟,我一眼就瞅见你代码里的问题了——你的isExpired变量是在AuthService类外面初始化的,而且只执行一次!
问题根源
你看你的auth.service.ts代码片段:
const helper = new JwtHelperService(); const myRawToken = localStorage.getItem('token'); const isExpired = helper.isTokenExpired(myRawToken); @Injectable() export class AuthService { ... public isAuthenticated(): boolean { return !isExpired; } }
这段代码里,isExpired在服务加载(也就是应用启动)的时候就计算好了,之后再也不会自动更新。你登录成功把新token存进localStorage后,这个变量还是原来的旧值(启动时没有token,所以isExpired是true,isAuthenticated()返回false),路由守卫自然会把你拦去401页面。而刷新页面时,服务会重新初始化,这时候才会读取新token计算isExpired,所以就能正常进入首页了。
修复方案
1. 把token检查逻辑移到isAuthenticated()方法内部
每次调用这个方法时,都实时读取最新的token并判断是否过期,而不是依赖一个固定不变的变量:
@Injectable() export class AuthService { private jwtHelper = new JwtHelperService(); // 把helper改成类的私有属性,更符合封装规范 ... public isAuthenticated(): boolean { const currentToken = localStorage.getItem('token'); // 先判断token是否存在,再检查是否过期 return !!currentToken && !this.jwtHelper.isTokenExpired(currentToken); } }
2. 处理Authorization头的前缀(可选但很重要)
通常后端返回的Authorization头格式是Bearer <你的token>,如果你直接存这个完整字符串,JwtHelperService可能无法正确解析token。所以登录时要把前缀去掉:
tap(resp => { const authHeader = resp.headers.get('Authorization'); // 提取纯token,去掉Bearer前缀(注意空格) const cleanToken = authHeader ? authHeader.replace(/^Bearer\s+/, '') : ''; localStorage.setItem('token', cleanToken); this.router.navigate(['']); })
3. 优化路由守卫(可选,更符合Angular规范)
把canActivate的返回类型改成Observable<boolean | UrlTree>,这样可以更灵活地处理跳转逻辑:
@Injectable() export class AuthGuardService implements CanActivate { constructor(private auth: AuthService, private router: Router) {} canActivate(): Observable<boolean | UrlTree> { if (!this.auth.isAuthenticated()) { // 返回UrlTree比直接调用navigate更符合Angular路由守卫的设计规范 return of(this.router.createUrlTree(['401'])); } return of(true); } }
效果验证
修改完之后,你登录成功存完token,调用this.router.navigate([''])时,路由守卫会调用isAuthenticated(),这时会读取最新的token并判断未过期,就会允许你进入首页,不用再刷新页面了。
内容的提问来源于stack exchange,提问作者Anton Rodrigues
相关产品推荐
相关产品推荐

