이 게시물에는 코드작성이 포함되어 있습니다. 소스코드를 받으신 후 진행해 주세요. MEAN Stack/개발 환경 구축에서 설명된 프로그램들(git, npm, atom editor)이 있어야 아래의 명령어들을 실행할 수 있습니다.
이 게시물의 소스코드는 기본사이트 만들기 / 회원가입 만들기에서 이어집니다.
angular-site.git 을 clone 한 적이 있는 경우: 터미널에서 해당 폴더로 이동 후 아래 명령어들을 붙여넣기합니다. 폴더 내 모든 코드가 이 게시물의 코드로 교체됩니다. 이를 원치 않으시면 이 방법을 선택하지 마세요.
angular-site.git 을 clone 한 적이 없는 경우: 터미널에서 코드를 다운 받을 폴더로 이동한 후 아래 명령어들을 붙여넣기하여 angular-site.git 을 clone 합니다.
- Github에서 소스코드 보기: https://github.com/a-mean-blogger/angular-site/tree/73fd793eba32db7f113a84e5d3fa8d5e98f1edaf
사이트의 회원 목록을 보여주는 page를 만들고 이 페이지에는 로그인된 사용자만 접근할 수 있게 해봅시다.
로그인되지 않은 사용자가 접근하려고 하면 아래 그림처럼 에러메세지를 내게 됩니다.
Angular 2에서는 Guard라는 것으로 route에 접근을 허가/불허가 하게 할 수 있습니다.
Angular 2에서 guard class는 CanActivate라는 interface class를 구현(implement)하여, canActivate라는 함수에 접근을 허가할지(true 리턴), 접근을 거부할지(false 리턴) 결정하는 코드를 넣게 됩니다. Routing module의 canActivate 항목에 guard를 넣을 수 있고, 해당 route에 접근하면 guard의 canActivate함수의 결과에 따라 접근이 허가 또는 불허됩니다.
참고로 CanDeactivate 인터페이스를 구현해서 CanDeactivate 함수를 가진 guard클라스를 만들어 route의 canDeactivate 항목에 넣으면 CanActivate와 반대로 현재 page를 떠날 수 있을 지 없을 지를 결정하게 됩니다.
이번 강의에서는 가입된 회원들의 리스트를 보여주는 페이지를 만들고 CanActivate를 구현한 auth guard를 만들어서 로그인된 유저만 해당 route에 접근할 수 있게 하겠습니다.
주황색은 변경된 파일, 녹색은 새로 생성된 파일, 회색은 변화가 없는 파일입니다.
아래 명령어로 guard.ts를 생성합니다.
$ ng g guard auth
아래 명령어로 user-index component도 생성해 줍시다.
$ ng g component user-index --spec false
--spec false
를 options으로 사용하면 .spec.ts를 생성하지 않습니다.
우선 user-index.component 파일들입니다.
// src/app/user-index/user-index.component.ts import { Component, OnInit } from '@angular/core'; import { User } from '../user'; import { UserService } from '../user.service'; @Component({ selector: 'app-user-index', templateUrl: './user-index.component.html', styleUrls: ['./user-index.component.css'] }) export class UserIndexComponent implements OnInit { users: User[]; constructor( private userService: UserService, ) { this.userService.index() .then(users => this.users = users ) .catch(response => null); } ngOnInit() { } }
userService의 index함수를 통해 가입된 모든 회원들의 목록을 가져옵니다.
<!-- src/app/user-index/user-index.component.html --> <div class="page page-users"> <div class="contentBox"> <h3 class="contentBoxTop">Users</h3> <ul> <ng-container *ngIf="users == null || users.length == 0"> <div class="noData" colspan=100> There is no user yet.</div> </ng-container> <li *ngFor="let user of users"> <a [routerLink]="['/','users',user.username]">{{user.username}}</a> </li> </ul> </div> </div>
ngFor를 사용하여 리스트를 보여줍니다.
/* src/app/user-index/user-index.component.css */ ul{ margin: 0; padding: 3px 12px; } ul:after { content: ""; display: block; clear: both; } ul li{ display: inline-block; list-style-type: none; float:left; } ul li a{ display: inline-block; text-decoration:none; margin: 3px; background-color: #eee; padding: 3px 10px; border-radius: 3px; } ul li a:hover{ background-color: #ccc; }
css 설명은 생략합니다.
다음으로 오늘 강의의 핵심은 auth.guard.ts를 살펴보죠. ng g guard auth
명령어를 사용하면 CanActivate를 구현(implement)해서 canActivate 함수를 가지고 있는 @Injectable()
클라스가 생성됩니다.
나머지 필요한 부분을 채우면 됩니다.
// src/app/auth.guard.ts import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; import { Observable } from 'rxjs/Observable'; import { AuthService } from './auth.service'; @Injectable() export class AuthGuard implements CanActivate { constructor( private router: Router, private authService: AuthService, ) { } canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean { if(this.authService.isLoggedIn()){ return true; } else{ alert("Please login first"); this.router.navigate(['login'],{ queryParams: { redirectTo: state.url } }); return false; } } }
우리는 authService의 isLoggedIn함수를 이용하여 현재 로그인이 된 상태인지 아닌지를 알 수 있습니다.
로그인이 된 상태라면 true를 리턴하여 접근을 허가하고, 아니라면 에러메세지를 띄운 후 login 페이지로 보냅시다. 그리고 redirectTo라는 query에 현재 url를 저장해서 로그인이 되면 바로 다시 돌아올 수 있게 하였습니다.
다음으로 app-routing.module.ts, app.module.ts를 살펴봅시다.
// src/app/app-routing.module.ts import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AuthGuard } from './auth.guard'; import { WelcomeComponent } from './welcome/welcome.component'; import { Error404Component } from './error404/error404.component'; import { LoginComponent } from './login/login.component'; import { UserNewComponent } from './user-new/user-new.component'; import { UserIndexComponent } from './user-index/user-index.component'; const routes: Routes = [ { path: '', component: WelcomeComponent }, { path: 'login', component: LoginComponent }, { path: 'users/new', component: UserNewComponent }, { path: 'users', canActivate: [AuthGuard], //1 children: [ { path: '', component: UserIndexComponent }, ] }, { path: '**', component: Error404Component }, ]; @NgModule({ imports: [ RouterModule.forRoot(routes) ], exports: [ RouterModule ] }) export class AppRoutingModule {}
1. users route에 canActivate로 AuthGuard가 들어간 것을 볼 수 있습니다. 이 users route에는 children을 만들어서 ' ' path에 UserIndexComponent를 넣었는데요, 이렇게 하면 users를 포함한 하위 route 전체에 이 AuthGuard가 적용됩니다. users route에는 나중에 페이지들이 더 추가될 예정입니다.
// src/app/app.module.ts //...생략 import { AppRoutingModule } from './app-routing.module'; import { AuthGuard } from './auth.guard'; //1 //...생략 import { UserNewComponent } from './user-new/user-new.component'; import { UserIndexComponent } from './user-index/user-index.component'; //2 @NgModule({ declarations: [ //... 생략 UserNewComponent, UserIndexComponent, //2 ], //...생략 providers: [ { provide: HTTP_INTERCEPTORS, useClass: RequestInterceptor, multi: true, }, AuthGuard, //1 UtilService, AuthService, UserService, ], bootstrap: [AppComponent] }) export class AppModule { }
1. AuthGuard는 @Injectable()
이므로 providers에 넣습니다.
2. Component는 declarations에 넣습니다.
Angular-CLI 명령어 사용해서 서버를 실행합시다.
ng serve --open
로그인이 되지 않은 상태에서 Users 메뉴를 클릭해봅시다.
이제 로그인을 하고 다시 Users 메뉴를 클릭해 봅시다.
아무 문제 없이 페이지가 로딩되었습니다.
눈썰미가 좋으신 분들은 Users 메뉴를 눌렀을 때 아래와 같은 화면이 잠깐 보이는 것을 눈치 채셨을 겁니다.
다음 강의에서는 이 부분에 대해 알아보도록 하겠습니다.
댓글
이 글에 댓글을 다시려면 SNS 계정으로 로그인하세요. 자세히 알아보기