mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Using a module for the authentification
This commit is contained in:
parent
c0243c8404
commit
81bdb69aac
@ -12,11 +12,7 @@ import { SearchResolverService } from "./services/search-resolver.service";
|
|||||||
import {ShowResolverService} from './services/show-resolver.service';
|
import {ShowResolverService} from './services/show-resolver.service';
|
||||||
import {StreamResolverService} from "./services/stream-resolver.service";
|
import {StreamResolverService} from "./services/stream-resolver.service";
|
||||||
import {ShowDetailsComponent} from './show-details/show-details.component';
|
import {ShowDetailsComponent} from './show-details/show-details.component';
|
||||||
import {LoginComponent} from "./login/login.component";
|
import {AuthGuard} from "./auth/misc/authenticated-guard.service";
|
||||||
import {UnauthorizedComponent} from "./unauthorized/unauthorized.component";
|
|
||||||
import {LogoutComponent} from "./logout/logout.component";
|
|
||||||
import {AutologinComponent} from "./autologin/autologin.component";
|
|
||||||
import {AuthGuard} from "./misc/guards/authenticated-guard.service";
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: "browse", component: BrowseComponent, pathMatch: "full", resolve: { shows: LibraryResolverService }, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")]},
|
{path: "browse", component: BrowseComponent, pathMatch: "full", resolve: { shows: LibraryResolverService }, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")]},
|
||||||
@ -26,17 +22,13 @@ const routes: Routes = [
|
|||||||
{path: "people/:people-slug", component: CollectionComponent, resolve: { collection: PeopleResolverService }, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")]},
|
{path: "people/:people-slug", component: CollectionComponent, resolve: { collection: PeopleResolverService }, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")]},
|
||||||
{path: "watch/:item", component: PlayerComponent, resolve: { item: StreamResolverService }, canLoad: [AuthGuard.forPermissions("play")], canActivate: [AuthGuard.forPermissions("play")]},
|
{path: "watch/:item", component: PlayerComponent, resolve: { item: StreamResolverService }, canLoad: [AuthGuard.forPermissions("play")], canActivate: [AuthGuard.forPermissions("play")]},
|
||||||
{path: "search/:query", component: SearchComponent, resolve: { items: SearchResolverService }, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")]},
|
{path: "search/:query", component: SearchComponent, resolve: { items: SearchResolverService }, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")]},
|
||||||
{ path: "login", component: LoginComponent },
|
|
||||||
{ path: "logout", component: LogoutComponent },
|
|
||||||
{ path: "autologin", component: AutologinComponent },
|
|
||||||
{ path: "unauthorized", component: UnauthorizedComponent },
|
|
||||||
{path: "**", component: NotFoundComponent}
|
{path: "**", component: NotFoundComponent}
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes,
|
imports: [RouterModule.forRoot(routes,
|
||||||
{
|
{
|
||||||
scrollPositionRestoration: "enabled"
|
scrollPositionRestoration: "enabled",
|
||||||
})],
|
})],
|
||||||
exports: [RouterModule],
|
exports: [RouterModule],
|
||||||
providers: [
|
providers: [
|
||||||
|
@ -3,10 +3,10 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
import { Event, Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router';
|
import { Event, Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router';
|
||||||
import * as $ from "jquery";
|
import * as $ from "jquery";
|
||||||
import { Location } from "@angular/common";
|
import { Location } from "@angular/common";
|
||||||
import {AuthService} from "./services/auth.service";
|
|
||||||
import {MatDialog} from "@angular/material/dialog";
|
import {MatDialog} from "@angular/material/dialog";
|
||||||
import {AccountComponent} from "./account/account.component";
|
|
||||||
import {Account} from "../models/account";
|
import {Account} from "../models/account";
|
||||||
|
import {AccountComponent} from "./auth/account/account.component";
|
||||||
|
import {AuthService} from "./auth/auth.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule} from '@angular/common/http';
|
import {HttpClientModule} from '@angular/common/http';
|
||||||
import {APP_INITIALIZER, ChangeDetectorRef, NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatRippleModule } from '@angular/material/core';
|
import { MatRippleModule } from '@angular/material/core';
|
||||||
@ -23,34 +23,17 @@ import { PlayerComponent } from './player/player.component';
|
|||||||
import { SearchComponent } from './search/search.component';
|
import { SearchComponent } from './search/search.component';
|
||||||
import { ShowDetailsComponent } from './show-details/show-details.component';
|
import { ShowDetailsComponent } from './show-details/show-details.component';
|
||||||
import { ShowsListComponent } from './shows-list/shows-list.component';
|
import { ShowsListComponent } from './shows-list/shows-list.component';
|
||||||
import { LoginComponent } from './login/login.component';
|
|
||||||
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
|
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
|
||||||
import { MatInputModule } from "@angular/material/input";
|
import { MatInputModule } from "@angular/material/input";
|
||||||
import { MatFormFieldModule } from "@angular/material/form-field";
|
import { MatFormFieldModule } from "@angular/material/form-field";
|
||||||
import {MatTabsModule} from "@angular/material/tabs";
|
import {MatTabsModule} from "@angular/material/tabs";
|
||||||
import {PasswordValidator} from "./misc/password-validator";
|
import {PasswordValidator} from "./misc/password-validator";
|
||||||
import {MatCheckboxModule} from "@angular/material/checkbox";
|
import {MatCheckboxModule} from "@angular/material/checkbox";
|
||||||
import {
|
|
||||||
AuthModule,
|
|
||||||
ConfigResult,
|
|
||||||
OidcConfigService,
|
|
||||||
OidcSecurityService,
|
|
||||||
OpenIdConfiguration
|
|
||||||
} from "angular-auth-oidc-client";
|
|
||||||
import { AccountComponent } from './account/account.component';
|
|
||||||
import { UnauthorizedComponent } from './unauthorized/unauthorized.component';
|
|
||||||
import { LogoutComponent } from './logout/logout.component';
|
|
||||||
import {MatDialogModule} from '@angular/material/dialog';
|
import {MatDialogModule} from '@angular/material/dialog';
|
||||||
import {FallbackDirective} from "./misc/fallback.directive";
|
import {FallbackDirective} from "./misc/fallback.directive";
|
||||||
import {AuthGuard} from "./misc/guards/authenticated-guard.service";
|
import {AuthModule} from "./auth/auth.module";
|
||||||
import { AutologinComponent } from './autologin/autologin.component';
|
import {AuthRoutingModule} from "./auth/auth-routing.module";
|
||||||
import {AuthorizerInterceptor} from "./misc/authorizer-interceptor.service";
|
|
||||||
import { AuthPipe } from './misc/auth.pipe';
|
|
||||||
|
|
||||||
export function loadConfig(oidcConfigService: OidcConfigService)
|
|
||||||
{
|
|
||||||
return () => oidcConfigService.load_using_stsServer(window.location.origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -64,18 +47,13 @@ export function loadConfig(oidcConfigService: OidcConfigService)
|
|||||||
SearchComponent,
|
SearchComponent,
|
||||||
PeopleListComponent,
|
PeopleListComponent,
|
||||||
ShowsListComponent,
|
ShowsListComponent,
|
||||||
LoginComponent,
|
|
||||||
PasswordValidator,
|
PasswordValidator,
|
||||||
AccountComponent,
|
FallbackDirective
|
||||||
UnauthorizedComponent,
|
|
||||||
LogoutComponent,
|
|
||||||
FallbackDirective,
|
|
||||||
AutologinComponent,
|
|
||||||
AuthPipe
|
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
|
AuthRoutingModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
MatSnackBarModule,
|
MatSnackBarModule,
|
||||||
@ -95,56 +73,8 @@ export function loadConfig(oidcConfigService: OidcConfigService)
|
|||||||
FormsModule,
|
FormsModule,
|
||||||
MatTabsModule,
|
MatTabsModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
AuthModule.forRoot()
|
AuthModule
|
||||||
],
|
|
||||||
entryComponents: [
|
|
||||||
AccountComponent
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
OidcConfigService,
|
|
||||||
{
|
|
||||||
provide: APP_INITIALIZER,
|
|
||||||
useFactory: loadConfig,
|
|
||||||
deps: [OidcConfigService],
|
|
||||||
multi: true
|
|
||||||
},
|
|
||||||
AuthGuard.guards,
|
|
||||||
{
|
|
||||||
provide: HTTP_INTERCEPTORS,
|
|
||||||
useClass: AuthorizerInterceptor,
|
|
||||||
multi: true
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule
|
export class AppModule { }
|
||||||
{
|
|
||||||
constructor(private oidcSecurityService: OidcSecurityService, private oidcConfigService: OidcConfigService, http: HttpClient)
|
|
||||||
{
|
|
||||||
this.oidcConfigService.onConfigurationLoaded.subscribe((configResult: ConfigResult) =>
|
|
||||||
{
|
|
||||||
const config: OpenIdConfiguration = {
|
|
||||||
stsServer: configResult.customConfig.stsServer,
|
|
||||||
redirect_url: "/",
|
|
||||||
post_logout_redirect_uri: "/logout",
|
|
||||||
client_id: 'kyoo.webapp',
|
|
||||||
response_type: "code",
|
|
||||||
trigger_authorization_result_event: true,
|
|
||||||
scope: "openid profile offline_access kyoo.read kyoo.play",
|
|
||||||
silent_renew: false,
|
|
||||||
silent_renew_url: "/silent",
|
|
||||||
use_refresh_token: false,
|
|
||||||
start_checksession: true,
|
|
||||||
|
|
||||||
forbidden_route: '/Forbidden',
|
|
||||||
unauthorized_route: '/Unauthorized',
|
|
||||||
log_console_warning_active: true,
|
|
||||||
log_console_debug_active: true
|
|
||||||
};
|
|
||||||
|
|
||||||
this.oidcSecurityService.setupModule(config, configResult.authWellknownEndpoints);
|
|
||||||
});
|
|
||||||
|
|
||||||
http.get("/api/account/default-permissions").subscribe((result: string[]) => AuthGuard.defaultPermissions = result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {Component, ElementRef, Inject, ViewChild} from '@angular/core';
|
import {Component, ElementRef, Inject, ViewChild} from '@angular/core';
|
||||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
import {Account} from "../../models/account";
|
|
||||||
import {HttpClient} from "@angular/common/http";
|
import {HttpClient} from "@angular/common/http";
|
||||||
|
import {Account} from "../../../models/account";
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
19
src/app/auth/auth-routing.module.ts
Normal file
19
src/app/auth/auth-routing.module.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
import {RouterModule, Routes} from "@angular/router";
|
||||||
|
import {UnauthorizedComponent} from "./unauthorized/unauthorized.component";
|
||||||
|
import {LoginComponent} from "./login/login.component";
|
||||||
|
import {LogoutComponent} from "./logout/logout.component";
|
||||||
|
import {AutologinComponent} from "./autologin/autologin.component";
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{path: "login", component: LoginComponent},
|
||||||
|
{path: "logout", component: LogoutComponent},
|
||||||
|
{path: "autologin", component: AutologinComponent},
|
||||||
|
{path: "unauthorized", component: UnauthorizedComponent},
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AuthRoutingModule { }
|
115
src/app/auth/auth.module.ts
Normal file
115
src/app/auth/auth.module.ts
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import {APP_INITIALIZER, NgModule} from '@angular/core';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
import {AccountComponent} from "./account/account.component";
|
||||||
|
import {AuthPipe} from "./misc/auth.pipe";
|
||||||
|
import {AutologinComponent} from "./autologin/autologin.component";
|
||||||
|
import {UnauthorizedComponent} from "./unauthorized/unauthorized.component";
|
||||||
|
import {LogoutComponent} from "./logout/logout.component";
|
||||||
|
import {LoginComponent} from "./login/login.component";
|
||||||
|
import {ConfigResult, OidcConfigService, OidcSecurityService, OpenIdConfiguration, AuthModule as OidcModule} from "angular-auth-oidc-client";
|
||||||
|
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule} from "@angular/common/http";
|
||||||
|
import {AuthGuard} from "./misc/authenticated-guard.service";
|
||||||
|
import {AuthorizerInterceptor} from "./misc/authorizer-interceptor.service";
|
||||||
|
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||||
|
import {MatIconModule} from "@angular/material/icon";
|
||||||
|
import {MatInputModule} from "@angular/material/input";
|
||||||
|
import {AppComponent} from "../app.component";
|
||||||
|
import {MatDialogModule} from "@angular/material/dialog";
|
||||||
|
import {MatButtonModule} from "@angular/material/button";
|
||||||
|
import {BrowserModule} from "@angular/platform-browser";
|
||||||
|
import {AppRoutingModule} from "../app-routing.module";
|
||||||
|
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||||
|
import {MatSnackBarModule} from "@angular/material/snack-bar";
|
||||||
|
import {MatProgressBarModule} from "@angular/material/progress-bar";
|
||||||
|
import {MatSelectModule} from "@angular/material/select";
|
||||||
|
import {MatMenuModule} from "@angular/material/menu";
|
||||||
|
import {MatSliderModule} from "@angular/material/slider";
|
||||||
|
import {MatTooltipModule} from "@angular/material/tooltip";
|
||||||
|
import {MatRippleModule} from "@angular/material/core";
|
||||||
|
import {MatCardModule} from "@angular/material/card";
|
||||||
|
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
|
||||||
|
import {MatTabsModule} from "@angular/material/tabs";
|
||||||
|
import {MatCheckboxModule} from "@angular/material/checkbox";
|
||||||
|
|
||||||
|
export function loadConfig(oidcConfigService: OidcConfigService)
|
||||||
|
{
|
||||||
|
return () => oidcConfigService.load_using_stsServer(window.location.origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AutologinComponent,
|
||||||
|
AuthPipe,
|
||||||
|
AccountComponent,
|
||||||
|
UnauthorizedComponent,
|
||||||
|
LogoutComponent,
|
||||||
|
LoginComponent,
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatSelectModule,
|
||||||
|
MatMenuModule,
|
||||||
|
MatSliderModule,
|
||||||
|
MatTooltipModule,
|
||||||
|
MatRippleModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatDialogModule,
|
||||||
|
FormsModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
OidcModule.forRoot()
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
AccountComponent
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
OidcConfigService,
|
||||||
|
{
|
||||||
|
provide: APP_INITIALIZER,
|
||||||
|
useFactory: loadConfig,
|
||||||
|
deps: [OidcConfigService],
|
||||||
|
multi: true
|
||||||
|
},
|
||||||
|
AuthGuard.guards,
|
||||||
|
{
|
||||||
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
useClass: AuthorizerInterceptor,
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AuthModule
|
||||||
|
{
|
||||||
|
constructor(private oidcSecurityService: OidcSecurityService, private oidcConfigService: OidcConfigService, http: HttpClient)
|
||||||
|
{
|
||||||
|
this.oidcConfigService.onConfigurationLoaded.subscribe((configResult: ConfigResult) =>
|
||||||
|
{
|
||||||
|
const config: OpenIdConfiguration = {
|
||||||
|
stsServer: configResult.customConfig.stsServer,
|
||||||
|
redirect_url: "/",
|
||||||
|
post_logout_redirect_uri: "/logout",
|
||||||
|
client_id: 'kyoo.webapp',
|
||||||
|
response_type: "code",
|
||||||
|
trigger_authorization_result_event: true,
|
||||||
|
scope: "openid profile offline_access kyoo.read kyoo.play",
|
||||||
|
silent_renew: false,
|
||||||
|
silent_renew_url: "/silent",
|
||||||
|
use_refresh_token: false,
|
||||||
|
start_checksession: true,
|
||||||
|
|
||||||
|
forbidden_route: '/Forbidden',
|
||||||
|
unauthorized_route: '/Unauthorized',
|
||||||
|
log_console_warning_active: true,
|
||||||
|
log_console_debug_active: true
|
||||||
|
};
|
||||||
|
|
||||||
|
this.oidcSecurityService.setupModule(config, configResult.authWellknownEndpoints);
|
||||||
|
});
|
||||||
|
|
||||||
|
http.get("/api/account/default-permissions").subscribe((result: string[]) => AuthGuard.defaultPermissions = result);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import {AuthService} from "../services/auth.service";
|
import {AuthService} from "../auth.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-autologin',
|
selector: 'app-autologin',
|
@ -3,7 +3,6 @@ import {ActivatedRoute, Router} from "@angular/router";
|
|||||||
import {catchError} from "rxjs/operators";
|
import {catchError} from "rxjs/operators";
|
||||||
import {EMPTY} from "rxjs";
|
import {EMPTY} from "rxjs";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import {HttpClient} from "@angular/common/http";
|
||||||
import {MatSnackBar} from "@angular/material/snack-bar";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
@ -20,7 +19,7 @@ export class LoginComponent
|
|||||||
loginErrors: [{code: string, description: string}];
|
loginErrors: [{code: string, description: string}];
|
||||||
registerErrors: [{code: string, description: string}];
|
registerErrors: [{code: string, description: string}];
|
||||||
|
|
||||||
constructor(private router: Router, private route: ActivatedRoute, private http: HttpClient, private snackBar: MatSnackBar)
|
constructor(private router: Router, private route: ActivatedRoute, private http: HttpClient)
|
||||||
{
|
{
|
||||||
if (this.route.snapshot.queryParams["ReturnUrl"])
|
if (this.route.snapshot.queryParams["ReturnUrl"])
|
||||||
this.redirectURI = this.route.snapshot.queryParams["ReturnUrl"];
|
this.redirectURI = this.route.snapshot.queryParams["ReturnUrl"];
|
@ -1,5 +1,4 @@
|
|||||||
import {Injector, Pipe, PipeTransform} from '@angular/core';
|
import {Injector, Pipe, PipeTransform} from '@angular/core';
|
||||||
import {AuthService} from "../services/auth.service";
|
|
||||||
import {HttpClient, HttpHeaders} from "@angular/common/http";
|
import {HttpClient, HttpHeaders} from "@angular/common/http";
|
||||||
import {OidcSecurityService} from "angular-auth-oidc-client";
|
import {OidcSecurityService} from "angular-auth-oidc-client";
|
||||||
|
|
||||||
@ -8,7 +7,7 @@ import {OidcSecurityService} from "angular-auth-oidc-client";
|
|||||||
})
|
})
|
||||||
export class AuthPipe implements PipeTransform
|
export class AuthPipe implements PipeTransform
|
||||||
{
|
{
|
||||||
private oidcSecurity: OidcSecurityService
|
private oidcSecurity: OidcSecurityService;
|
||||||
|
|
||||||
constructor(private injector: Injector, private http: HttpClient) {}
|
constructor(private injector: Injector, private http: HttpClient) {}
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
|||||||
Router
|
Router
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
import {AuthService} from "../../services/auth.service";
|
import {AuthService} from "../auth.service";
|
||||||
|
|
||||||
@Injectable({providedIn: "root"})
|
@Injectable({providedIn: "root"})
|
||||||
export class AuthGuard
|
export class AuthGuard
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import {AuthService} from "../services/auth.service";
|
import {AuthService} from "../auth.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-unauthorized',
|
selector: 'app-unauthorized',
|
Loading…
x
Reference in New Issue
Block a user