Angular 17技术问题:无法阻止未认证用户访问受保护路由
Angular 17路由认证守卫问题
我在Angular 17中配置了路由,需求是:未认证用户默认重定向至登录页面,已认证用户跳转至home路由。通过home.guard检查localStorage中的认证token,但登出后仍可访问所有子路由的HTML内容(仅无法加载数据,因为API需要token)。预期逻辑是:已认证则进入home路由,否则跳转至登录页。已经花了近5小时查博客和视频都没解决,想问是否需要使用authResolver?
当前路由代码
import { CanActivate, CanActivateChild } from './guards/home.guard'; export const routes: Routes = [ { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: 'login', title: 'Login', component:LoginComponent, }, { path: 'signup', title: 'Sign Up', component:SignupComponent, }, { path: '', component:SidebarComponent, canActivateChild: [CanActivateChild], children:[ { path: 'dashboard', title: 'Dashboard Blank', component:DashboardHomeComponent, }, { path: 'profile', title: 'Profile', component:ProfileComponent, }, { path: 'home', title: 'Dashboard Demo', component:DashboardComponent, } ] }, ];
home.guard.ts代码
import { inject } from "@angular/core"; import { CanActivateFn, Router } from '@angular/router'; import { StorageService } from '../services/storage.service'; /** export const homeGuard: CanActivateFn = (route, state) => { return true; }; */ export const CanActivate = () => { const storageService = inject(StorageService); const router = inject (Router); /** userData below is an array with elements such as user_id, firstname, lastname, token etc. **/ if (storageService.get('userData')) { return true; } else { router.navigate(['login']); return false; } } export const CanActivateChild = () => { CanActivate(); }
Storage Service代码
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class StorageService { constructor() {} // Store the value async store(storageKey: string, value: any) { localStorage.setItem(storageKey, JSON.stringify(value)); } // Get the value async get(storageKey: string) { let ret: any = localStorage.getItem( storageKey ); return ret ? JSON.parse(<string>ret) : null; } }
问题分析与修复方案
核心问题
- CanActivateChild守卫无返回值:当前
CanActivateChild函数仅调用CanActivate()但未返回其结果,导致守卫未生效,Angular默认允许访问所有子路由。 - 异步方法同步调用错误:
StorageService.get是异步方法,但守卫中同步调用,导致判断逻辑无法正确获取userData值。 - 根路由无认证检查:根路由直接重定向到home,未经过认证守卫校验,未认证用户会直接进入home路由的父组件。
修复步骤
1. 修复守卫函数
修改home.guard.ts,确保守卫符合Angular类型定义并正确返回结果:
import { inject } from "@angular/core"; import { CanActivateFn, CanActivateChildFn, Router } from '@angular/router'; import { StorageService } from '../services/storage.service'; // 主认证守卫逻辑 export const canActivate: CanActivateFn = (route, state) => { const storageService = inject(StorageService); const router = inject(Router); const userData = storageService.get('userData'); // 确保userData存在且包含有效token if (userData && userData.token) { return true; } else { router.navigate(['login']); return false; } }; // 子路由守卫复用主逻辑 export const canActivateChild: CanActivateChildFn = (route, state) => { return canActivate(route, state); };
2. 修正StorageService的异步冗余
localStorage是同步API,无需使用async,修改服务代码:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class StorageService { constructor() {} // 存储值 store(storageKey: string, value: any) { localStorage.setItem(storageKey, JSON.stringify(value)); } // 获取值 get(storageKey: string) { const ret = localStorage.getItem(storageKey); return ret ? JSON.parse(ret) : null; } }
3. 完善路由配置
给根路由和父路由添加认证守卫,确保所有受保护路由都经过校验:
import { canActivate, canActivateChild } from './guards/home.guard'; export const routes: Routes = [ { path: '', redirectTo: 'home', pathMatch: 'full', canActivate: [canActivate] // 根重定向需经过认证检查 }, { path: 'login', title: 'Login', component: LoginComponent }, { path: 'signup', title: 'Sign Up', component: SignupComponent }, { path: '', component: SidebarComponent, canActivate: [canActivate], // 父路由添加认证守卫,确保整个子路由组需认证 canActivateChild: [canActivateChild], children: [ { path: 'dashboard', title: 'Dashboard Blank', component: DashboardHomeComponent }, { path: 'profile', title: 'Profile', component: ProfileComponent }, { path: 'home', title: 'Dashboard Demo', component: DashboardComponent } ] }, // 404路由重定向到登录页(可选) { path: '**', redirectTo: 'login' } ];
是否需要使用authResolver?
不需要。Resolver的作用是在路由激活前预加载数据,而你的需求是路由访问权限控制,这正是CanActivate/CanActivateChild守卫的核心职责。当前问题完全是守卫配置错误导致的,修复守卫即可解决,无需使用Resolver。
内容的提问来源于stack exchange,提问作者techwestcoastsfosea
相关产品推荐
相关产品推荐

