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 应用程序。
用户通过身份验证后,如果用户具有管理员角色,则菜单项 - 电影、流派、演员和电影院会显示在菜单中,否则它们将保持隐藏状态。在我的 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 应用程序。