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

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;
  }
  
}

问题分析与修复方案

核心问题

  1. CanActivateChild守卫无返回值:当前CanActivateChild函数仅调用CanActivate()但未返回其结果,导致守卫未生效,Angular默认允许访问所有子路由。
  2. 异步方法同步调用错误:StorageService.get是异步方法,但守卫中同步调用,导致判断逻辑无法正确获取userData值。
  3. 根路由无认证检查:根路由直接重定向到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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 08:25:53