#angular #typescript #angular9
#angular #typescript #angular9
Вопрос:
Я новичок в angular и работаю над изменением кода.
В настоящее время код работает с использованием стандартного углового метода загрузки всех компонентов вместе, что означает, что несколько компонентов выполняют http-вызовы вместе.
Мое приложение angular размещено в службе приложений Azure с аутентификацией Azure ad, настроенной на портале azure.
начиная с 1-го пункта, я хочу улучшить и убедиться, что сначала, перед загрузкой любого компонента, я получаю параметр id_token из http://host/.auth/me url-адрес, который будет моим токеном авторизации.(Этот токен аутентификации в качестве заголовка аутентификации будет использоваться для выполнения вызовов api для серверной части)
Как только у меня будет этот токен аутентификации, я сохраню его в локальном / сеансовом хранилище. Только когда этот процесс будет завершен, я хочу приступить к загрузке других компонентов angular.
Я читал о отложенной загрузке компонента. но я хочу знать, что лучше всего делать в описанном выше сценарии.
Комментарии:
1. Вы должны попробовать использовать какой-то AuthGuard. Например, почему
loggedin$
в AuthGuard значение false, тогда не отображайте компоненты.
Ответ №1:
Ну, есть несколько способов сделать это
APP_INITIALIZER
Вы можете написать асинхронную функцию, загружающую токен, и внедрить эту функцию в основной модуль. Никакие компоненты не будут инициализированы до тех пор, пока обещание функции не будет выполнено. Этот способ прост, но уродлив. Пользователи будут видеть белый экран во время выполнения запроса токена.
@NgModule({
//...
providers: [
{
provide: APP_INITIALIZER,
useFactory: () => () => {
return fetch('https://token.provired.com/getToken')
.then(x => x.json())
.then(x => localStorage.setItem("token", x));
},
multi: true,
}
]
})
export class AppModule { }
Корневой компонент
Вы можете инициализировать запрос токена из корневого компонента, как правило, это app.cpmponent.ts
. В шаблоне компонента вы можете показывать некоторую разметку или счетчик во время выполнения запроса, чтобы пользователи знали, что приложение работает. Предполагается, что инициализация других компонентов должна быть заблокирована *ngIf
. Проверьте фрагмент ниже
@Component({
selector: 'app-root',
template: `
<div *ngIf="!tokenLoaded">Please wait</div>
<div *ngIf="tokenLoaded">
<app-my-component></app-my-component>
</div>`,
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
tokenLoaded = false;
ngOnInit(){
getToken().then(token => {
localStorage.setItem("token", token);
tokenLoaded = true;
})
}
}
Защита
Как упоминал @Gytis TG в комментариях, вы можете запустить запрос токена в guard. Преимущество этого подхода заключается в том, что у вас будет отдельный фрагмент кода, отвечающий за загрузку токена.
Ответ №2:
я думаю, у нас есть 2 идеи о том, как вы могли бы справиться с ограничением видимости для ваших компонентов.
в нашем приложении мы можем обрабатывать наш логин и другую аутентификацию в нашем auth.service.ts.
// auth.service.ts
@Injectable({
providedIn: 'root'
})
export class AuthService {
private token: string;
private loggedIn = false;
constructor(private http: HttpClient) {}
getLoggedIn() {
return this.loggedIn;
}
login(email:string, password:string): Promise <string> {
const promise = new Promise < string > ((resolve, reject) => {
const authData = { email: email, password: password }
this.http.post < { token: string } > (environment.backendUrl '/api/user/login', authData).toPromise()
.then(response => {
const token = response.token;
this.token = token;
if (token) {
this.loggedIn = true;
}
}
как вы можете видеть в приведенном выше фрагменте после успешного входа в систему, мы получаем токен в теле нашего ответа, который, я полагаю, аналогичен тому, как вы получаете токен в своем приложении. затем мы присваиваем этот response.token переменной token внутри нашего файла auth.service.ts. после того, как токен назначен переменной внутри файла auth.service.ts, мы можем прочитать его и проверить наличие токена, вызвав функцию getLoggedIn() из любого места приложения, импортировав файл auth.service.ts.
теперь вернемся к тому, как можно ограничить видимость компонентов, проверяя наличие токена. один из способов — мы можем импортировать наш файл auth.service.ts в компонент, где мы хотим ограничить видимость компонента, добавив его в конструктор следующим образом
// .ts file where you want to restrict visibility
export class component {
loggedIn = false;
constructor(private authService: AuthService) {}
ngOnInit() {
this.loggedIn = this.authService.getLoggedIn();
}
вы можете видеть, что компонент проверяет наличие токена во время вызова ngOnInit. это означает, что в нашем соответствующем html-файле мы можем использовать эту переменную LoggedIn с *ngIf для ограничения видимости определенных элементов html или даже всего компонента, если это необходимо
// .html file
<div *ngIf=loggedIn>
<h1> title </h1>
<p> here you be your text </p>
</div>
другой способ — реализовать защиту, как упоминали ранее Михаил и Гитис. эта защита проверяет наличие токена перед перенаправлением на страницу, чтобы убедиться, что только пользователи, вошедшие в систему, могут посещать определенные страницы. мы можем сделать это, добавив файл auth.guard.ts, подобный этому:
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean | Observable < boolean > | Promise < boolean > {
const loggedIn = this.authService.getLoggedIn();
if (!loggedIn) {
this.router.navigate(['/login']);
}
return loggedIn;
}
}
после добавления этого файла мы можем включить проверку токенов в нашем файле app-routing.ts следующим образом.
// app-routing.ts file
const routes: Routes = [
{ path: "", component: HomePageComponent },
{ path: "home", component: HomePageComponent },
{ path: "login", component: LoginPageComponent },
{ path: "signup", component: SignupPageComponent },
{ path: "profile/:id", component: ProfilePageComponent, canActivate: [AuthGuard] },
]
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [AuthGuard]
})
export class AppRoutingModule {}
в snipped страница профиля защищена AuthGuard, поэтому только зарегистрированные пользователи могут посещать эту страницу. если пользователь не вошел в систему, AuthGuard перенаправляет пользователя на страницу входа, поэтому, даже если вручную ввести URL-адрес в браузере, все равно необходимо войти в систему перед посещением страницы.
я тоже новичок в SO, но я изо всех сил старался написать для вас четкий ответ, надеясь, что смогу вам помочь! 🙂 хорошего дня!