AuthGuard CanActivate 无法在 app-routing.module.ts 中为在 angular .net 项目中具有管理员角色的经过身份验证的用户工作

AuthGuard CanActivate not working in app-routing.module.ts for an authenticated user with role as admin in angular .net project

用户通过身份验证后,如果用户具有管理员角色,则菜单项 - 电影、流派、演员和电影院会显示在菜单中,否则它们将保持隐藏状态。在我的 WEBAPI returns 角色成为“管理员”之后,菜单项仍然隐藏。我无法弄清楚这个问题。

app-routing.module.ts

                import { RegisterComponent } from './security/register/register.component';
            import { UserIndexComponent } from './security/user-index/user-index.component';
            import { MovieDetailsComponent } from './movies/movie-details/movie-details.component';
            import { NgModule } from '@angular/core';
            import { RouterModule, Routes } from '@angular/router';
            import { CreateActorComponent } from './actors/create-actor/create-actor.component';
            import { EditActorComponent } from './actors/edit-actor/edit-actor.component';
            import { IndexActorsComponent } from './actors/index-actors/index-actors.component';
            import { CreateGenreComponent } from './genres/create-genre/create-genre.component';
            import { EditGenreComponent } from './genres/edit-genre/edit-genre.component';
            import { IndexGenresComponent } from './genres/index-genres/index-genres.component';
            import { HomeComponent } from './home/home.component';
            import { CreateMovieTheaterComponent } from './movie-theaters/create-movie-theater/create-movie-theater.component';
            import { EditMovieTheaterComponent } from './movie-theaters/edit-movie-theater/edit-movie-theater.component';
            import { IndexMovieTheaterComponent } from './movie-theaters/index-movie-theater/index-movie-theater.component';
            import { CreateMovieComponent } from './movies/create-movie/create-movie.component';
            import { EditMovieComponent } from './movies/edit-movie/edit-movie.component';
            import { MovieFilterComponent } from './movies/movie-filter/movie-filter.component';
            import { IsAdminGuard } from './is-admin.guard';
            import { LoginComponent } from './security/login/login.component';

            const routes: Routes = [
              {path:'', component:HomeComponent},
              {path:'genres', component:IndexGenresComponent, canActivate:[IsAdminGuard]},
              {path:'genres/create', component:CreateGenreComponent, canActivate:[IsAdminGuard]},
              {path:'genres/edit/:id', component:EditGenreComponent, canActivate:[IsAdminGuard]},
              {path:'actors', component:IndexActorsComponent, canActivate:[IsAdminGuard]},

              {path:'actors/create', component:CreateActorComponent, canActivate:[IsAdminGuard]},
              {path:'actors/edit/:id', component:EditActorComponent, canActivate:[IsAdminGuard]},
              {path:'movietheaters', component:IndexMovieTheaterComponent, canActivate:[IsAdminGuard]},
              {path:'movietheaters/create', component:CreateMovieTheaterComponent, canActivate:[IsAdminGuard]},
              {path:'movietheaters/edit/:id', component:EditMovieTheaterComponent, canActivate:[IsAdminGuard]},

              {path:'movies/create', component:CreateMovieComponent, canActivate:[IsAdminGuard]},
              {path:'movies/edit/:id', component:EditMovieComponent, canActivate:[IsAdminGuard]},
              {path:'movies/filter', component:MovieFilterComponent},
              {path: 'movies/id', component:MovieDetailsComponent},
              {path: 'register', component:RegisterComponent},
              {path: 'login', component:LoginComponent},
              {path:'users',component:UserIndexComponent,canActivate:[IsAdminGuard]},

              // {path:'**',component:HomeComponent}
              {path:'**',redirectTo:' '}


            ];

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

            export class AppRoutingModule { }

            // @NgModule({
            //   imports: [RouterModule.forRoot(routes
            //     // ,
            //     // { enableTracing: true } // <-- debugging purposes only
            //     )],
            //   exports: [RouterModule]
            // })

是-admin.guard.ts

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

          import { Observable } from 'rxjs';
          import { SecurityService } from './security/security.service';

          @Injectable({
            providedIn: 'root'
          })
          export class IsAdminGuard implements CanActivate {
          /**
            *
            */
          constructor(private securityService:SecurityService,private router:Router) { }


            canActivate(
              route: ActivatedRouteSnapshot,
              state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

                if(this.securityService.getRole()==='admin'){
                  return true;
                }
                this.router.navigate(['/login']);
              return false;
            }

          }

menu.component.html

        <mat-toolbar color="primary">
        <span>
            <a routerLink=" " mat-button>
            <mat-icon>local_movies</mat-icon>
            Angular Movies
            </a>
        </span>
        <div>
            <a mat-button routerLink="movies/filter">
            <mat-icon>search</mat-icon>Search Movies
            </a>
        </div>
        <app-authorize-view [role]="'admin'">
          <ng-container authorized>
            <div>
              <a mat-button routerLink="genres">
                  Genres
              </a>
          </div>
          <div>
              <a mat-button routerLink="actors">
                  Actors
              </a>
          </div>
          <div>
              <a mat-button routerLink="movietheaters">
                  Movie Theaters
              </a>
          </div>
          <div>
              <a mat-button routerLink="movies/create">
                  Create Movie
              </a>
          </div>
          <div>
            <a mat-button routerLink="users">
                Users
            </a>
        </div>

          </ng-container>
        </app-authorize-view>
    <div class="space"></div>
    <app-authorize-view>
      <ng-container authorized>
        <span>Hello,{{securityService.getFieldFromJWT('email')}}</span>
        <a mat-button (click)="securityService.logout()">Logout</a>
      </ng-container>
      <ng-container notAuthorized>
      <a mat-button routerLink="login">Login</a>
      <a mat-button routerLink="register">Register</a>
    </ng-container>
    </app-authorize-view>
    </mat-toolbar>

menu.component.ts

    import { SecurityService } from './../security/security.service';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-menu',
  templateUrl: './menu.component.html',
  styleUrls: ['./menu.component.css']
})
export class MenuComponent implements OnInit {

  constructor(public securityService:SecurityService) { }

  ngOnInit(): void {
  }

}

app.component.html

        <app-menu>
      
    </app-menu>
    <div class="container">
    
    <router-outlet></router-outlet>

    </div>

app.component.ts

        import { Component, OnInit } from '@angular/core';
    import { ActivatedRoute, Router } from '@angular/router';
    import { SecurityService } from './security/security.service';

    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit {
      title(title: any) {
      }
      constructor(
        private securityService: SecurityService,
        private router: Router,
        private activatedRoute: ActivatedRoute
      ) {}

    ngOnInit(): void {

    }

    shouldRedirectToUser(): boolean{
      if (this.securityService.isAuthenticated()){
        return true;
      }
      console.log(this.router.url);
      console.log(this.activatedRoute.url);
      return false;
    }

   }

授权-view.component.html

    <ng-content *ngIf="!isAuthorized()" select=[notAuthorized]></ng-content>
<ng-content *ngIf="isAuthorized()" select=[authorized]></ng-content>

授权-view.component.ts

      import { Component, Input, OnInit } from '@angular/core';
  import { SecurityService } from '../security.service';

  @Component({
    selector: 'app-authorize-view',
    templateUrl: './authorize-view.component.html',
    styleUrls: ['./authorize-view.component.css'],
  })
  export class AuthorizeViewComponent implements OnInit {
    constructor(private securityService: SecurityService) {}

    @Input()
    role: string;
    ngOnInit(): void {}

    public isAuthorized() {
      if (this.role) {
        // console.log(this.role);
        return this.securityService.getRole() === this.role;
      } else {
        //console.log(this.securityService.isAuthenticated());

        return this.securityService.isAuthenticated();
      }
    }
  }

jwt-interceptor.services

      import { SecurityService } from 'src/app/security/security.service';
  import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
  import { Injectable } from '@angular/core';
  import { Observable } from 'rxjs';

  @Injectable({
    providedIn: 'root'
  })
  export class JwtInterceptorService implements HttpInterceptor{
    constructor(private securityService:SecurityService) { }
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
      const token=this.securityService.getToken();
      if(token){
        req=req.clone({
          setHeaders:{Authorization:`Bearer ${token}`}
        });
      }
      return next.handle(req);
    }
  }

security.models.ts

      export interface userCredentisals
  {
    email:string;
    password:string;
  }

  export interface authenticationResponse{
    token:string;
    expiration:Date;
  }

  export interface userDTO{
    id:string;
    email:string;
  }

security.service.ts

        import { Observable } from 'rxjs';
    import { authenticationResponse, userCredentisals, userDTO } from './security.models';
    import { Injectable } from '@angular/core';
    import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
    import { environment } from 'src/environments/environment';

    @Injectable({
      providedIn: 'root'
    })
    export class SecurityService {

      constructor(private http:HttpClient) { }
      private apiURL=environment.apiURL+"/accounts";
      private readonly expirationTokenKey:string='token-expiration';
      private readonly tokenKey:string='token';
      private readonly roleField:string='role';

      isAuthenticated():boolean{
        const token = localStorage.getItem(this.tokenKey);

        if(!token){
          return false;
        }
        const expiration=localStorage.getItem(this.expirationTokenKey);
        const expirstionDate=new Date(expiration);
        if(expirstionDate<=new Date){
          this.logout();
          return false;
        }
        return true;
      }

      getFieldFromJWT(field:string):string{
    const token=localStorage.getItem(this.tokenKey);
    if(!token){return '';}
    const dataToken=JSON.parse(atob(token.split('.')[1]));
    return dataToken[field];
      }
      logout(){
        localStorage.removeItem(this.tokenKey);
        localStorage.removeItem(this.expirationTokenKey)
      }
      getRole():string{
        return this.getFieldFromJWT(this.roleField);
      }

      saveToken(authenticationResponse:authenticationResponse){
        localStorage.setItem(this.tokenKey,authenticationResponse.token);
        localStorage.setItem(this.expirationTokenKey,authenticationResponse.expiration.toString());
      }
      register(userCredentisals:userCredentisals): Observable<authenticationResponse>{
        return this.http.post<authenticationResponse>(this.apiURL+"/create",userCredentisals);
      }
      login(userCredentisals:userCredentisals): Observable<authenticationResponse>{
        return this.http.post<authenticationResponse>(this.apiURL+"/login",userCredentisals);
      }

      getToken(){
        return localStorage.getItem(this.tokenKey);
      }

      getUsers(page:number, recordsPerPage:number):Observable<any>{
        let params=new HttpParams();
        params=params.append('page',page.toString());
        params=params.append('recordsPerPage,',recordsPerPage.toString());
        return this.http.get<userDTO[]>(`${this.apiURL}/listusers`,{observe:'response',params});

      }
      makeAdmin(userId:string){
      const headers= new HttpHeaders('Content-Type: application/json');
      return this.http.post(`${this.apiURL}/makeadmim`,JSON.stringify(userId),{headers});
      }
      removeAdmin(userId:string){
        const headers= new HttpHeaders('Content-Type: application/json');
        return this.http.post(`${this.apiURL}/removeadmim`,JSON.stringify(userId),{headers});
      }
    }

app.module.ts

    import { NgModule } from '@angular/core';
import {HttpClientModule, HTTP_INTERCEPTORS} from '@angular/common/http'
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MoviesListComponent } from './movies/movies-list/movies-list.component';
import { GenericListComponent } from './utilities/generic-list/generic-list.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
// import {LeafletModule} from '@asymmetrik/ngx-leaflet'
import {LeafletModule} from '@asymmetrik/ngx-leaflet';
// import 'leaflet/dist/images/marker-shadow.png';

////////////////////

import { icon, Marker } from 'leaflet';
const iconRetinaUrl = 'src/assets/marker-icon-2x.png';
const iconUrl = 'src/assets/marker-icon.png';
const shadowUrl = 'src/assets/marker-shadow.png';
const iconDefault = icon({
  iconRetinaUrl,
  iconUrl,
  shadowUrl,
  iconSize: [25, 41],
  iconAnchor: [12, 41],
  popupAnchor: [1, -34],
  tooltipAnchor: [16, -28],
  shadowSize: [41, 41]
});
Marker.prototype.options.icon = iconDefault;


//////////////////////////

// import * as L from 'leaflet'
// import 'leaflet/dist/leaflet.css';

// // stupid hack so that leaflet's images work after going through webpack
// import marker from 'leaflet/dist/images/marker-icon.png';
// import marker2x from 'leaflet/dist/images/marker-icon-2x.png';
// import markerShadow from 'leaflet/dist/images/marker-shadow.png';

// // delete L.Icon.Default.prototype._getIconUrl;

// L.Icon.Default.mergeOptions({
//     iconRetinaUrl: marker2x,
//     iconUrl: marker,
//     shadowUrl: markerShadow
// });





///////
//  import 'leaflet/dist/images/marker-shadow.png';
////////////////////////////////
//  import img from '.'
//import { Map, latLng, tileLayer, Layer, marker, icon } from '@asymmetrik/ngx-leaflet';
// import 'leaflet/dist/images/marker-shadow.png';

///////////////////////////
import {MarkdownModule} from 'ngx-markdown';
import { MaterialModule } from './material/material.module';
import { MenuComponent } from './menu/menu.component';
import { RatingComponent } from './utilities/rating/rating.component';
import { LifecycletestComponent } from './lifecycletest/lifecycletest.component';
import { HomeComponent } from './home/home.component';
import { IndexGenresComponent } from './genres/index-genres/index-genres.component';
import { CreateGenreComponent } from './genres/create-genre/create-genre.component';
import { IndexActorsComponent } from './actors/index-actors/index-actors.component';
import { CreateActorComponent } from './actors/create-actor/create-actor.component';
import { IndexMovieTheaterComponent } from './movie-theaters/index-movie-theater/index-movie-theater.component';
import { CreateMovieTheaterComponent } from './movie-theaters/create-movie-theater/create-movie-theater.component';
import { CreateMovieComponent } from './movies/create-movie/create-movie.component';
import { EditActorComponent } from './actors/edit-actor/edit-actor.component';
import { EditGenreComponent } from './genres/edit-genre/edit-genre.component';
import { EditMovieTheaterComponent } from './movie-theaters/edit-movie-theater/edit-movie-theater.component';
import { EditMovieComponent } from './movies/edit-movie/edit-movie.component';
import { FormGenreComponent } from './genres/form-genre/form-genre.component';
import { MovieFilterComponent } from './movies/movie-filter/movie-filter.component';
import { CommonModule } from '@angular/common';
import { FormActorComponent } from './actors/form-actor/form-actor.component';
import { InputImgComponent } from './utilities/input-img/input-img.component';
import { InputMarkdownComponent } from './utilities/input-markdown/input-markdown.component';
import { MovieTheaterFormComponent } from './movie-theaters/movie-theater-form/movie-theater-form.component';
import { MapComponent } from './utilities/map/map.component';
import { FormMovieComponent } from './movies/form-movie/form-movie.component';
import { MultipleSelectorComponent } from './utilities/multiple-selector/multiple-selector.component';
import { ActorsAutocompleteComponent } from './actors/actors-autocomplete/actors-autocomplete.component';
import { DisplayErrorsComponent } from './utilities/display-errors/display-errors.component';
import { SweetAlert2Module } from '@sweetalert2/ngx-sweetalert2';
import { MovieDetailsComponent } from './movies/movie-details/movie-details.component';
import { AuthorizeViewComponent } from './security/authorize-view/authorize-view.component';
import { LoginComponent } from './security/login/login.component';
import { RegisterComponent } from './security/register/register.component';
import { AuthenticationFormComponent } from './security/authentication-form/authentication-form.component';
import { JwtInterceptorService } from './security/jwt-interceptor.service';
import { UserIndexComponent } from './security/user-index/user-index.component';
//import { ActorsComponent } from './actors/actors/actors.component';
@NgModule({
  declarations: [
    AppComponent,
    MoviesListComponent,
    GenericListComponent,
    MenuComponent,
    RatingComponent,
    LifecycletestComponent,
    HomeComponent,
    IndexGenresComponent,
    CreateGenreComponent,
    IndexActorsComponent,
    CreateActorComponent,
    IndexMovieTheaterComponent,
    CreateMovieTheaterComponent,
    CreateMovieComponent,
    EditActorComponent,
    EditGenreComponent,
    EditMovieTheaterComponent,
    EditMovieComponent,
    FormGenreComponent,
    MovieFilterComponent,
    FormActorComponent,
    InputImgComponent,
    InputMarkdownComponent,
    MovieTheaterFormComponent,
    MapComponent,
    FormMovieComponent,
    MultipleSelectorComponent,
    ActorsAutocompleteComponent,
    DisplayErrorsComponent,
    MovieDetailsComponent,
    AuthorizeViewComponent,
    LoginComponent,
    RegisterComponent,

    AuthenticationFormComponent,
    UserIndexComponent,

  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MaterialModule,
    ReactiveFormsModule,
    CommonModule,
    FormsModule ,
    HttpClientModule,
    MarkdownModule.forRoot(),
    LeafletModule,
    SweetAlert2Module.forRoot()
  ],
  providers: [{
    
    provide:HTTP_INTERCEPTORS,
    useClass:JwtInterceptorService,
    multi:true

  }],
  bootstrap: [AppComponent]
})
export class AppModule { }

login.component.html

      <app-display-errors [errors]="errors"></app-display-errors>
  <app-authentication-form [action]="'Login'" (onSubmit)="login($event)"></app-authentication-form>

login.component.ts

      import { parseWebAPIErrors } from 'src/app/utilities/utils';
  import { Router } from '@angular/router';
  import { userCredentisals, authenticationResponse } from './../security.models';
  import { SecurityService } from './../security.service';
  import { Component, OnInit } from '@angular/core';

  @Component({
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.css']
  })
  export class LoginComponent implements OnInit {

    constructor(private securityService:SecurityService,private router:Router) { }
  errors:string[]=[];
    ngOnInit(): void {
    } 
  login(userCredentisals:userCredentisals){
  this.securityService.login(userCredentisals).subscribe(authenticationResponse=>{
  this.securityService.saveToken(authenticationResponse);
  this.router.navigate(['/']);
  },error=>this.errors=parseWebAPIErrors(error));

  }
  }

我在 stackblitz 中 post 将此代码编辑为节点项目因为我在 stackblitz 的免费试用订阅下我无法 post 来自 github 的项目作为 angular,stackbliz中的所有代码都在app文件夹下。请原谅我 - 一切对我来说都是新的 - angular、stackblitz 和 github。我没有 post 编辑 WEBAPI 项目,因为我不能 post DB 和 WEBAPI 项目,比如 stackblitz,所以只有 angular 代码可以作为节点项目使用 stackblitz。我也在 VSCODE 中调试了 WEBAPI 和 agular 代码,没有错误 - WEBAPI returns 角色作为 angular 项目的“管理员”,但未显示菜单项在用户被认证为角色 -:admin 之后。我在这里缺少什么?

这是 stackblitz link Project in stackblitz

我忘记将值 claimtype 和 claim value 以及 userId 放在 .net Identity 的 [AspNetUserClaims] table 中。我正在为 WebAPI 使用 JSON 网络令牌 jwtToken,并将数据库中的声明添加到令牌中,如果用户是管理员操作菜单,则令牌用于签入 angular 应用程序。