이제 guard 라는 걸 할건데 진짜 말 그대로 생각하면 됨. 클럽 가드처럼 생각하자. 오우 빻! 빠꾸! 와 같은 느낌으로
라우팅이나 컴포넌트 작업을 하기 전에 확인을 하는거지. 뭐 예를 들어서 어떤거에 접근을 하려고 해 그런데 나는 모두에게 public 하게 공개하고싶지 않은 컨텐츠야. 그러면 우리는 메인페이지에서 어떤 컨텐츠 눌렀을 때에 회원이나 어떤 등급 이상만 접근 권한이 있습니다 이딴 소리 많이 들어봤을 거야. 그런 역할을 해주는거야. 어떤 작업을 하기 전에 조건을 확인을 하고 동작을 하도록 하는 거지. 말로만 백날 해봐야 이해가 되나, 바로 들어가자
ng g g auth 라는 걸 만들자. 에이~ 약자를 또 설명해야되려나?ㅇㅇ 내가 까먹을거같음
ng generate guard auth. 의 약자임.
하여튼 일단 그렇게 하고, 나는 CanActivate로 갈거야. 지금은 어떤 기능을 실행하는 거에 대해서 권한을 부여하는 것이기 때문에 이걸 선택.
그러면 이렇게 2개가 생성이 됩니다잉
auth.guard.ts를 보자
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return true;
}
}
Angular 버전11에서는 route: 라는 부분이 변경이 된거임. 예전에는 next: 이런 식으로 되어있었다.
근데 아무리 봐도 지저분한 코드는 못참지. auth.guard.ts의 내용을 조금 변경해보자
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return true;
}
}
이제 app.module.ts에 등록을 해줘야지
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { BoardComponent } from './board/board.component';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './auth.guard';
const router : Routes = [ //라우팅
{path : 'login' , component : LoginComponent},
{path : 'board' , component : BoardComponent, canActivate: [AuthGuard]}, // board 갈 때에 guard 한 번 넣자
{path : '', redirectTo : '/login', pathMatch : 'full'}
]
@NgModule({
declarations: [
AppComponent,
LoginComponent,
BoardComponent
],
imports: [
BrowserModule,
RouterModule.forRoot(router, {enableTracing:false, useHash: true}),
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
이제 넣긴 했는데 서버에 응답 요청을 하는 서비스를 만들어보자
ng g s ask 여기서 s는 누가 봐도 service. ask라는 서비스를 만든거야. 물론 얘도 src/app 까지 와서 해야겠지
ask에서 id 비번 치라는걸 할건데 일단 이 기능 자체는 login이라는 컴포넌트를 만들어놨으니까 거기 login.component.ts랑 login.component.html에 아이디 비번 넣는 거를 만들어놓자
login.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
id : string; // 아이피 필드
passwd : string; // 비번 필드
constructor() { }
ngOnInit(): void {
}
// 직접적인 로그인을 하는 함수
login() {
console.log(this.id, this.passwd);
}
}
login.component.html
<input type="text" placeholder="id" [(ngModel)]='id' />
<input type="text" placeholder="password" [(ngModel)]='passwd'/>
<input type="button" value="로그인" (click)='login()'/>
ㅇ이거 하면 일단 오류난다. 전에 ngModel 은 바로 뭐 하는게 아니라서 가져와야 하는 부분 있었음. 아이씨 그거 찾아옴 ㅎ 현타올뻔했네 ㅇㅋ 어떤게 오류냐면 우리는 ngIf나 ngFor 이런 것들을 쓰고 ngModel을 쓰기 위해서는 FormsModule을 들여와야한다. module을 들여온다? app.module.ts를 찾아 가서 추가해줘야겠지
app.module.ts파일에 imports: [ ]에 FormsModule을 추가해준다. 그런다면 일단 우리의 프로젝트에서는 이런 식으로 되어 있겠지
imports: [
BrowserModule,
RouterModule.forRoot(router, {enableTracing:false, useHash: true}),
FormsModule,
],
이제 설정이 끝났으니 ask.service.ts 에 기능을 만들어볼까
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AskService {
private readonly storage = {
id: 'admin',
pwd: '1234'
}
constructor() { }
tryToLogin(parameter : any){
return new Observable( checking=> { // 검사할 놈 생성
if( // 이건 id, pwd 전부 다 맞게 친 경우
(parameter.id == this.storage.id) && // id 검사
(parameter.pwd == this.storage.pwd) // pwd 검사
){
checking.next({status: true});
localStorage.setItem('status', "true");
} else{ // 둘 중 하나라도 다른 경우
checking.next({status: false, reason: 'wrong login information'});
}
checking.complete;
});
}
}
이거 login 컴포넌트에서 subscribe해서 보자.
login.component.ts
import { Component, OnInit } from '@angular/core';
import { AskService } from '../ask.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
id : string; // 아이피 필드
pwd : string; // 비번 필드
constructor(private service: AskService) { }
// constructor 그러니까 생성시에 바로 저 AskService 넣어가지고 하는거
ngOnInit(): void {
}
// 직접적인 로그인을 하는 함수
login() { // private servicd 거기서 아까 만든 tryToLogin 때려
this.service.tryToLogin({id: this.id, pwd: this.pwd })
.subscribe(checking => { // subscribe 하셈
console.log(checking);
});
}
}
엥 돌렸는데 왜 오류가 나지 했는데 ㅈㅅ 내가 login.component.ts랑 login.component.html에서 passwd를 다 pwd로 바꿈..
변수명 한 번에 바꾸는 방법 적어놓을게. 변수가 선택된 상태로(드래그나 Shift누르는거 있잖아) ⌘ + ⇧ + L 하면 해당 변수가 한 번에 선택되고 그 상태로 바꾸면 뒤도 전부 바뀜..ㅋ ㅈㅅ
로그인을 이제 가드 거쳐서 하는 방법을 볼건데 일단 우리가 localData로 id,pwd 가지고 있는 다 했는데 이걸 세션으로 일단 가지고있어보자. ask.service.ts파일 수정 한다.
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AskService {
private readonly storage = {
id: 'admin',
pwd: '1234'
}
constructor() { }
// 읽기만 할 수 있는거 -> 로그인이 되어있는지 모는거징
readonly isLogged: BehaviorSubject<boolean> = new BehaviorSubject(false);
tryToLogin(parameter : any){
return new Observable( checking=> { // 검사할 놈 생성
if( // 이건 id, pwd 전부 다 맞게 친 경우
(parameter.id == this.storage.id) && // id 검사
(parameter.pwd == this.storage.pwd) // pwd 검사
){
checking.next({status: true});
localStorage.setItem('status', "true");
} else{ // 둘 중 하나라도 다른 경우
checking.next({status: false, reason: 'wrong login information'});
}
checking.complete;
});
}
// 로그인 되어있니?를 물어보는거지
loggedIn() : void{
if(localStorage.getItem('status') == 'true'){ // 로컬 저장소에 status값이 true 면
this.isLogged.next(true); // 로그인 되어있습니다
}else{
this.isLogged.next(false); // 응 아니야
}
}
}
그래 이거 해놨으면 이제 guard를 바꿔야지
auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { AskService } from './ask.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
private status: boolean= false; // status
constructor(private service : AskService){
service.isLogged.subscribe( result => { // login 되어있는지 확인하는 대상을 구독한다고.
console.log('서버에 물어보고온 결과', result);
this.status = result; // 업데이트
});
}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
this.service.loggedIn(); // 로그인 되어있습니까?
return this.status;
}
}
자 다 왔어 얼른 이런 ㅂ신 같은거 끝내고 firebase나 연동하고싶은거 알아 기다려
login.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AskService } from '../ask.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
id : string; // 아이피 필드
pwd : string; // 비번 필드
constructor(private service: AskService, private router: Router) {
// private 해서 다른 컴포넌트나 html에서는 접근 불가
}
// constructor 그러니까 생성시에 바로 저 AskService 넣어가지고 하는거
ngOnInit(): void {
}
// 직접적인 로그인을 하는 함수
login() { // private servicd 거기서 아까 만든 tryToLogin 때려
this.service.tryToLogin({id: this.id, pwd: this.pwd })
.subscribe((checking:any) => { // subscribe 하셈
console.log(checking);
this.router.navigate(['/board']); // 라우터 객체를 통해서 다른 컴포넌트로 이동하는건 navigate(['원하는 경로']) 하면 됨
});
}
}
'Angular > Angular' 카테고리의 다른 글
Angular 11 + firebase(firestore) 프로젝트 #08 routing (0) | 2020.12.10 |
---|---|
Angular 11 + firebase(firestore) 프로젝트 #08 데이터 바인딩(dashboard) (0) | 2020.12.09 |
Angular 11 + firebase(firestore) 프로젝트 #06 (0) | 2020.12.09 |
Angular 11 + firebase(firestore) 프로젝트 #05 여러 component 가져오기 (0) | 2020.12.09 |
Angular 11 프로젝트 #04 - 로그인, 초기 오류 문제 (0) | 2020.12.08 |