개요
어플리케이션에서 사용자의 로그인을 요구하는 것은, 사용자의 정보를 바탕으로 어플리케이션에서 맞춤 정보를 제공하기 위해서 입니다. 예를 들어 어플리케이션에 따라서는 사용자의 로그인 여부에 따라, 혹은 사용자의 등급에 따라 정보에 대한 접근을 제한해야 하는 경우도 있습니다. 대표적인 경우가 어플리케이션의 관리자 페이지에 대한 접근 제한입니다.
이를 위해서는 앞선 포스트에서 보았던 것처럼 사용자의 Login 상태에 따라 화면 및 링크를 숨겨 접근을 차단 할 수도 있습니다.
<mat-card *ngIf="auth.user | async as user">
하지만 이러한 방법을 모든 컴포넌트에 적용하게 되면 설정이 여기저기 산재되어 지속적인 유지 관리가 쉽지 않습니다.
이번 포스트에서는 Angular 에서 제공하는 Router 모듈을 이용하여 입력받은 URL 에 따라 표시할 수 있는 컴포넌트를 변경하고, Guard 를 추가하여 로그인한 사용자만 특정 컴포넌트에 접근할 수 있도록 해보겠습니다.
Angular Project 시작
$ ng new my-app
컴포넌트 생성
이번 포스트에서 작성해볼 Angular 어플리케이션은 사용자가 입력한 주소에 따라 컴포넌트를 화면에 표시합니다.
Angular CLI 를 사용하여 home, login, phaser 컴포넌트를 생성합니다.
$ ng g c home
$ ng g c login
$ ng g c phaser
각 컴포넌트의 내용은 추후에 작성합니다. 이번 시간에는 Router 모듈의 기능을 살펴보는 것에 중점을 둡니다.
AppRoutingModule 추가
새로 생성한 컴포넌트를 사용자의 입력 및 브라우저의 주소값에 따라 표시하는 기능은 Angular 의 Router 모듈에서 제공해줍니다. Router 모듈을 사용하여 주소값에 따라 화면에 표시되는 컴포넌트를 변경하도록 합니다. 이를 Angular 에서 사용할 수 있는 가장 좋은 방법은 별도의 최상위 모듈에서 Router 를 불러 설정하는 것입니다.
편의를 위하여 이 모듈의 이름은 AppRoutingModule 로 생성하겠습니다. Angular CLI 를 사용하여 /src/app/app-routing
폴더에 app-routing.module.ts
파일을 생성합니다.
$ ng g m app-routing
Routing 설정
이번에는 Angular Application 에서 주소(URL)와 컴포넌트를 어떻게 연결할지 정의합니다. 이를 위해 방금 생성한 AppRoutingModule 의 폴더(/src/app/app-routing
) 에 별도로 routes.ts
파일을 만든 후, 아래의 내용을 추가합니다.
▼ /src/app/app-routing/routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from '../home/home.component';
import { LoginComponent } from '../login/login.component';
import { PhaserComponent } from '../phaser/phaser.component';
export const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path : 'phaser', component: PhaserComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' }
];
화면에 표시할 컴포넌트들을 등록한 후, Routes
배열을 만들 사용자가 입력할 주소와 함께 나열하였습니다,
이처럼 Routes
배열은 일반적으로 두 개의 속성값을 가지고 있습니다.
하나는 path
이고 다른 하나는 component
입니다. path
는 웹브라우저의 URL 을 의미하여 component
는 해당 URL 을 입력받았을 때, 표시할 컴포넌트입니다. 예를 들어 위 설정은 localhost:4200/login 이라고 주소창에 입력할 경우 로그인 컴포넌트가 화면에 표시되게 됩니다.
주의할 할 점은 Routes 에 대한 정의는 위에서부터 한줄씩 비교하여 일치할 경우, 동작하기 때문에 구체적이고 좁은 범위의 주소값을 위쪽에, 포괄적이고 넓은 범위의 주소값을 아래쪽에 배치합니다.
Router 등록
방금 구성한 Routes
배열을 바탕으로 Angular Application 이 동작하도록 AppRoutingModule 모듈을 설정합니다.
우선 별도의 @angular/router
라이브러리에서 RouterModule 과 Routes 를 등록 합니다. 그리고 이 중 RouterModule 은 @NgModule.exports 에 추가하여 AppModule 의 컴포넌트에서 필요시 라우터 지시자를 사용할 수 있도록 합니다.
앞서 구성한 Routes
배열은 RouterModule.forRoot()
메소드에 전달합니다. Angular 의 Router 서비스는 Angular 어플리케이션이 실행되면 현재 브라우저의 URL 을 기반으로 Routes
배열을 검색하여 일치하는 컴포넌트를 화면에 표시합니다.
최종 코드는 아래와 같습니다.
▼ /src/app/app-routing/app-routing.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
// ↓ 추가
import { RouterModule, Routes } from '@angular/router';
import { routes } from './routes';
@NgModule({
declarations: [],
imports: [
CommonModule,
// ↓ 추가
RouterModule.forRoot(routes)
],
// ↓ 추가
exports: [ RouterModule ],
})
export class AppRoutingModule { }
Router Outlet 추가
<router-outlet></router-outlet>
은 Router 모듈이 입력받은 주소값에 따라서 컴포넌트를 교체하는 위치를 표시하는 지시자입니다. 이를 app.component.html
파일에 추가하도록 합니다.
▼ src/app/app.component.html
<router-outlet></router-outlet>
구성한 AppRouting Module을 AppModule 에서 사용할 수 있도록 app.module.ts
파일을 다음과 같이 갱신합니다.
▼ src/app/app.module.ts
.. 생략 ..
// ↓ 추가
import { AppRoutingModule } from './app-routing/app-routing.module';
@NgModule({
.. 생략 ..
imports: [
.. 생략 .. ,
// ↓ 추가
AppRoutingModule
],
.. 생략 ..
})
지금까지 작성한 코드를 동작시키면 다음과 같은 결과를 얻을 수 있습니다. 앞서 정의했던 주소에 따라 화면에 표시되는 컴포넌트가 변경되는 것을 확인할 수 있습니다.
▲ 라우팅 설정 동작 확인
Routing Guard 를 통한 접근 제어
Angular Router 는 지금까지 설정한 내용을 바탕으로 누구에게나 주소에 해당하는 컴포넌트에 접근할 수 있게 허가해줍니다. 앞서 언급한 것처럼 이번에는 라우터에 가드를 추가하여 로그인한 사용자만 컴포넌트에 접근할 수 있도록 설정해보겠습니다.
이번 예시에서는 앞서 생성한 컴포넌트 중 Phaser
컴포넌트에 대한 접근을 로그인한 사용자로 제한하겠습니다. 이를 위해 Agular CLI 로 가드를 생성하고, 가드의 이름은 로그인된 사용자의 여부를 확인하는 가드이므로 auth
라고 하겠습니다.
$ ng generate guard auth/auth
생성된 가드는 다음과 같이 수정 합니다.
▼ src/app/auth/auth.guard.ts
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
UserLogedIn : boolean;
constructor(private router: Router) {
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
console.log('AuthGuard#canActivate called');
if (this.UserLogedIn) {
return true;
}
// 로그인 하지 않은 경우, 자동으로 login 컴포넌트로 이동
this.router.navigate(['/login']);
return false;
}
}
이제 추가한 Guard 를 앞서 만들었던 routes 설정에 등록한 후, phaser
경로에 대해서 canActive guard 로 AuthGuard
를 등록합니다. 이를 통해 AuthGuard
의 함수값이 true
인 경우만 phaser 경로를 통해 Phaser
컴포넌트에 접근 할 수 있게 되었습니다.
▼ /src/app/app-routing/routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from '../home/home.component';
import { LoginComponent } from '../login/login.component';
import { PhaserComponent } from '../phaser/phaser.component';
// ↓ 추가
import { AuthGuard } from '../auth.guard';
export const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'login', component: LoginComponent },
// ↓ 변경
{ path : 'phaser', component: PhaserComponent, canActivate: [AuthGuard] },
{ path: '', redirectTo: '/home', pathMatch: 'full' }
];
작성한 라우팅 가드가 잘 동작하는지 확인해 봅니다.
주소창에 /phaser
를 입력하도록 합니다. 우리는 현재 로그인을 하지 않았기 때문에 Phaser
컴포넌트가 아닌 login
주소로 자동 이동하는 것을 확인할 수 있습니다.
Auth Guard 동작 확인 (1/2)
이번에는 간단히 라우팅 가드의 동작 기준이 되는 this.UserLogedIn
변수의 초기값을 true
로 변경하여 Auth Guard 의 동작을 확인 합니다.
▼ src/app/auth/auth.guard.ts
... 생략 ...
// ↓ 수정
UserLogedIn : boolean = true;
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (this.UserLogedIn) {
return true;
}
this.router.navigate(['/login']);
return false;
}
... 생략 ...
로그인 여부를 판단하는 변수를 임의로 로그인 상태로 변경하였기 때문에 Phaser
컴포넌트에 접근할 수 있는 것을 확인할 수 있습니다.
Auth Guard 동작 확인 (2/2)
종합
이제 라우팅 기능 및 라우팅 가드 기능이 잘 동작하는 것을 확인하였으므로 앞서 만들었던 Firebase Auth Service 와 Phaser 벽돌격파게임을 지금까지 만든 Routing 데모에 통합합니다.
라우팅 가드의 핵심 기능인 사용자의 로그인 여부는 AuthService
를 사용해 확인합니다.
▼ src/app/auth/auth.guard.ts
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service'; // ← 추가
@Injectable()
export class AuthGuard implements CanActivate {
UserLogedIn : boolean = false;
// ↓ 수정
constructor(private router: Router,
private auth: AuthService) {
this.auth.user.subscribe(res => {
if (res) {
console.log('user is logged in');
this.UserLogedIn = true;
} else {
console.log('user is not logged in');
this.UserLogedIn = false;
}
});
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (this.UserLogedIn) {
return true;
}
this.router.navigate(['/login']);
return false;
}ㅘ
}
Phaser
컴포넌트 및 Login
컴포넌트의 내용은 다음의 포스팅을 참고하여 화면 및 기능을 작성 합니다.
- Angular Firebase - 사용자 인증 (1/2)
- Angular Firebase - 사용자 인증 (2/2)
- Angular 와 Phaser 함께 사용하기 (1/2)
*Angular 와 Phaser 함께 사용하기 (2/2) - 벽돌깨기 게임 만들기
라우팅 기능이 동작하는 최종 소스코드 및 동작하는 데모는 다음의 링크에서 확인할 수 있습니다.
결론
이번 포스트에서는 기존에 작성하였던 로그인 화면과 Phaser 로 만든 벽돌격파 게임을 엮어서 하나의 웹 앱을 완성해보았습니다. Angular Router 서비스를 사용하여 해당 컴포넌트 별로 접근할 수 있는 URL을 부여하였으며 사용자의 로그인 여부에 따라 Phaser 컨텐츠에 접근을 제한하였습니다.
참고
'모듈, 프레임웍 > Angular' 카테고리의 다른 글
Angular 기초들 - 사용자입력 (0) | 2018.11.06 |
---|---|
Angular 외부 라이브러리 사용하기 (0) | 2018.09.27 |
Font Awesome @ Angular (0) | 2018.09.22 |
Flex Layout 사용하기 (0) | 2018.09.16 |
음악신청 게시판 만들기 (0) | 2018.09.15 |