Presentation is loading. Please wait.

Presentation is loading. Please wait.

MEAN Stack Front to Back (MEANAuthApp)

Similar presentations


Presentation on theme: "MEAN Stack Front to Back (MEANAuthApp)"— Presentation transcript:

1 MEAN Stack Front to Back (MEANAuthApp)
8. Login & Logout 9. Protected Requests & Auth Guard

2 목차 1. 환경 구축 2. Express Setup & Routes 3. User Model and Register
4. API authentication and Token 5. Angular 4 Components & Routes 6. Register Component, Validation & Flash messages 7. Auth Service & User Registration 8. Login & Logout 9. Protected Requests & Auth Guard 10. App Deployment to Heroku

3 8. Login & Logout

4 로그인 기능 추가 Login.component.html 에 로그인 폼 작성 Login 버튼 클릭시
<h2 class="page-header">Login </h2> <form (submit)="onLoginSubmit()">   <div class="form-group">     <label>Username</label>     <input type="text" class="form-control" [(ngModel)]="username" name="username">   </div>     <label>Password</label>     <input type="password" class="form-control" [(ngModel)]="password" name="password">   <input type="submit" class="btn btn-primary" value="Login"> </form> Login 버튼 클릭시 onLoginSubmit() 함수 실행 Username, password 값에 대해 2-way databinding 설정

5 Login.component.ts 파일 수정
import { Component, OnInit } from import { AuthService } from '../../services/auth.service'; import { Router } from import { FlashMessagesService } from 'angular2-flash-messages'; @Component({   selector: 'app-login',   templateUrl: './login.component.html',   styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit {   username: string;   password: string;   constructor(     private authService: AuthService,     private router: Router,     private flashMessage: FlashMessagesService   ) { }   ngOnInit() {   }   onLoginSubmit(){     const user = {       username: this.username,       password: this.password     }     this.authService.authenticateUser(user).subscribe(data => {       console.log(data);     }); } Login.component.ts 파일 수정 필요한 서비스 import 로그인에 필요한 변수 선언 Constructor에 서비스 등록 사용자 입력 값을 user 변수에 저장 Auth.service.ts에 authenticateUser() 함수 추가 예정 Subscribe 메서드로 옵저버 등록 테스트 서버에서 보내주는 data를 확인

6 로그인 기능 추가 auth.service.ts Auth.service에 authenticateUser 함수 선언
registerUser(user){   let headers = new Headers();   headers.append('Content-Type', 'application/json');   return this.http.post(' user, {headers: headers})     .map(res => res.json()); } authenticateUser(user){   return this.http.post(' user, {headers: headers}) Auth.service에 authenticateUser 함수 선언 - user 데이터를 ' 전송하고 응답을 받아옴

7 테스트 미등록된 사용자이름 패스워드 틀림 로그인 성공시 토큰과 사용자 정보 전송

8 authenticateUser 함수 Login.component.ts 파일의 authenticateUser 함수 작성
this.authService.authenticateUser(user).subscribe(data => {   if(data.success) {     this.authService.storeUserData(data.token, data.user);     this.flashMessage.show('You are now logged in', {cssClass: 'alert-success', timeout: 5000});     this.router.navigate(['dashboard']);   } else {     this.flashMessage.show(data.msg, {cssClass: 'alert-danger', timeout: 5000});     this.router.navigate(['login']);   } }); 로그인 성공시 - 토큰과 user 데이터를 로컬스토리지에 저장 (auth.service.ts에 storeUserData함수 작성 예정) - 로그인 성공 flashMessage 표시 - dashboard 페이지로 리다이렉트 로그인 실패시 - 로그인 실패 flashMessage 표시 - login 페이지로 리다이렉트

9 storeUserData 함수 Auth.service.ts 에 storeUserData 함수 선언 localStorage 에는
authenticateUser(user){   let headers = new Headers();   headers.append('Content-Type', 'application/json');   return this.http.post(' user, {headers: headers})     .map(res => res.json()); } storeUserData(token, user){   localStorage.setItem('id_token', token);   localStorage.setItem('user', JSON.stringify(user));   this.authToken = token;   this.user = user; localStorage 에는 string 형식으로 저장 token, user 데이터를 localStorage에 저장 token, user 데이터를 this.authToken, this.user 변수로 저장 (앱 내부에서 로그인 여부 확인을 위한 변수)

10 테스트 로그인 성공시 Dashboard 로 이동 localStorage에 토큰과 사용자정보 저장

11 로그아웃 기능 추가 Auth.service.ts 에 logout 함수 추가 로그인 변수의 값을 지우고 로컬스토리지를 비움
storeUserData(token, user){   localStorage.setItem('id_token', token);   localStorage.setItem('user', JSON.stringify(user));   this.authToken = token;   this.user = user; } logout(){   this.authToken = null;   this.user = null;   localStorage.clear(); 로그인 변수의 값을 지우고 로컬스토리지를 비움

12 로그아웃 기능 추가 UI에 Logout 버튼 추가 Navbar.component.html 파일 수정
<ul class="nav navbar-nav navbar-right">   <li [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}"><a [routerLinkActive]="['active']" [routerLink]="['/login']">Login</a></li>   <li [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}"><a [routerLinkActive]="['active']" [routerLink]="['/register']">Register</a></li>   <li><a (click)="onLogoutClick()" href="#">Logout</a></li> </ul> 메뉴에 Logout 버튼 추가 클릭하면 onLogoutClick() 함수 실행 Navbar.component.ts에 onLogoutClick() 함수 작성 예정

13 로그아웃 기능 추가 Navbar.component.ts 파일에 onLogoutClick() 함수 추가
import { Component, OnInit } from import { AuthService } from '../../services/auth.service'; import { Router } from import { FlashMessagesService } from 'angular2-flash-messages'; @Component({   selector: 'app-navbar',   templateUrl: './navbar.component.html',   styleUrls: ['./navbar.component.css'] }) export class NavbarComponent implements OnInit {   constructor(     private authService: AuthService,     private router: Router,     private flashMessage: FlashMessagesService   ) { }   ngOnInit() {   }   onLogoutClick(){     this.authService.logout();     this.flashMessage.show('You are logged out', {       cssClass: 'alert-success',       timeout: 3000     });     this.router.navigate(['/login']);     return false; } 이를 위해서는 authService, router, flashmessage 등의 서비스가 필요 Constructor에 서비스 등록 authService의 logout()함수 실행 로그아웃 flashMessage 표시 login 페이지로 리다이렉트 (router 서비스 이용)

14 로그아웃 테스트 login 페이지로 리다이렉트 localStorage의 토큰 정보가 삭제됨

15 9. Protected Requests & Auth Guard

16 Protected Request 페이지 요청에 대한 토큰인증 어떻게 설정하나?
로그인된 상태에서 토큰을 제시해야만 접근 가능한 페이지 설정 Dashboard 페이지는 로그인 상태에서만 접속 가능 Profile 페이지에는 토큰을 제시해야만 접근 허용 (서버에서 토큰 검증) 서버측 페이지에는 이미 토 큰 인증이 설정되어 있음 어떻게 설정하나? 로그인되면 토큰을 받음 Profile 페이지 요청시 토큰을 첨부하도록 수정

17 토큰인증 서비스 설정 Auth.service.ts 파일에서 getProfile() 함수에 토큰인증 서비스 추가
  let headers = new Headers();   this.loadToken();   headers.append('Authorization', this.authToken);   headers.append('Content-Type', 'application/json');   return this.http.get(' {headers: headers})     .map(res => res.json()); } storeUserData(token, user){   localStorage.setItem('id_token', token);   localStorage.setItem('user', JSON.stringify(user));   this.authToken = token;   this.user = user; loadToken(){   const token = localStorage.getItem('id_token'); Profile 페이지 접근을 위한 토큰인증 서비스 작성 토큰을 읽어와서authorization 헤더에 첨부 http.get 요청을 보내고 응답을 받아옴 localStorage에서 토큰을 읽어와서 this.authToken에 로드하는 함수

18 토큰인증 서비스를 profile.component에 적용
import { Component, OnInit } from import { AuthService } from '../../services/auth.service'; import { Router } from @Component({   selector: 'app-profile',   templateUrl: './profile.component.html',   styleUrls: ['./profile.component.css'] }) export class ProfileComponent implements OnInit {   user: Object;   constructor(     private authService: AuthService,     private router: Router   ) { }   ngOnInit() {     this.authService.getProfile().subscribe(profile => {         this.user = profile.user;       },       err => {         console.log(err);         return false;     });   }  } AuthService, Router 서비스 import AuthService, Router 서비스 등록 Profile 페이지를 열 때 authService.getProfile 서비스 적용 Subscribe 메서드로 observer 등록 서버에서 제공하는 사용자 정보를 적용

19 Profile 페이지 작성 Profile.component.html 페이지 로그인된 경우에만 사용자 정보를 표시
사용자 정보 user 가 존재하는 경우에만 div 영역을 생성 <div *ngIf="user">   <h2 class="page-header">{{user.name}}</h2>   <ul class="list-group">     <li class="list-group-item">Username: {{user.username}}</li>     <li class="list-group-item"> {{user. }}</li>   </ul> </div>

20 테스트 로그인 된 상태에서만 profile 페이지 접근 가능

21 패키지 버전 관리 (임시) JWT 인증 관련 최신버전에서 에러 발생 서버측 패키지를 이전 버전으로 관리
Package.json 파일에서 버전을 다음과 같이 수정 node_modules 폴더 삭제 > npm install 다시 실행 (수정된 버전으로 설치됨) "jsonwebtoken": "^7.4.1", "passport": "^0.3.2", "passport-jwt": "^2.2.1"

22 패키지 버전 관리 (임시) 버전업시 수정했던 것 원위치 Auth.service.ts 에서 토큰 이름 지정
서버측 route/users.js 수정 Jwt 토큰 생성시 json객체 형식의 데이터 입력 const token = jwt.sign({data: user}, config.secret, {  const token = jwt.sign(user, config.secret, { Auth.service.ts 에서 토큰 이름 지정 loggedIn(){ // return tokenNotExpired(); return tokenNotExpired('id_token'); }

23 로그인 여부에 따른 메뉴 표시 재조정 로그인된 경우 표시될 페이지 로그아웃된 경우 표시될 페이지
Home (항상 표시) Dashboard (추가) Profile (추가) Logout 로그아웃된 경우 표시될 페이지 Login Register 로그인/로그아웃 상태를 판단할 수 있는 기능 필요 토큰은 유효기간이 있어서 기간이 지나면 유효하지 않음 토큰이 유효한지 여부를 확인 필요

24 Angular2-jwt 패키지 이용 Angular2-jwt https://github.com/auth0/angular2-jwt
> npm install angular2-jwt

25 Angular2-jwt 패키지 이용 angular2-jwt 설치 (frontend에 설치)
> cd meanauthapp/angular-src > npm install angular2-jwt --save meanauthapp/angular-src/package.json 에 설치 확인 Auth.service.ts에 tokenNotExpired, loggedIn() 등록 import { Injectable } from import { Http, Headers } from import 'rxjs/add/operator/map'; import { tokenNotExpired } from 'angular2-jwt'; 중략 loadToken(){   const token = localStorage.getItem('id_token');   this.authToken = token; } loggedIn(){   return tokenNotExpired(); 토큰이 유효한지 여부를 확인하는 기능

26 Navbar.component.html 파일에 적용
로그인 되어 있으면 항목 표시 *ngIf="authService.loggedIn()“ 로그인 안된 경우 항목 표시 *ngIf=“!authService.loggedIn()" <ul class="nav navbar-nav navbar-right">   <li *ngIf="authService.loggedIn()" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}"><a [routerLinkActive]="['active']" [routerLink]="['/dashboard']">Dashboard</a></li>   <li *ngIf="authService.loggedIn()" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}"><a [routerLinkActive]="['active']" [routerLink]="['/profile']">Profile</a></li>   <li *ngIf="!authService.loggedIn()" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}"><a [routerLinkActive]="['active']" [routerLink]="['/login']">Login</a></li>   <li *ngIf="!authService.loggedIn()" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}"><a [routerLinkActive]="['active']" [routerLink]="['/register']">Register</a></li>   <li *ngIf="authService.loggedIn()"><a (click)="onLogoutClick()" >Logout</a></li> </ul>

27 로그인 안된 경우 접근 금지 설정 AuthGuard 서비스 설정 별도의 폴더 app/guards 생성
auth.guard.ts 생성 import { Injectable } from import { Router, CanActivate } from import { AuthService } from '../services/auth.service'; @Injectable() export class AuthGuard implements CanActivate { constructor(private authService: AuthService, private router: Router) { } canActivate(){ if(this.authService.loggedIn()){ return true; } else { this.router.navigate(['/login']); return false; 로그인 되어 있으면 canActivate가 true 리턴 로그인 안되어 있으면 로그인 페이지로 리다이렉트하고 canActivate가 false 리턴

28 App.module.ts에 auth.guard 적용
import { ValidateService } from './services/validate.service'; import { AuthService } from './services/auth.service'; import { FlashMessagesModule } from 'angular2-flash-messages'; import { AuthGuard } from './guards/auth.guard'; const appRoutes: Routes = [   {path:'', component: HomeComponent},   {path:'register', component: RegisterComponent},   {path:'login', component: LoginComponent},   {path:'dashboard', component: DashboardComponent, canActivate:[AuthGuard]},   {path:'profile', component: ProfileComponent, canActivate:[AuthGuard]} ] 중략…   providers: [ValidateService, AuthService, AuthGuard], dashboard와 profile 컴포넌트에 AuthGuard 적용

29 최종 사이트 테스트 (경) 성공! (축) 로그인시 메뉴 로그아웃시 메뉴 토큰인증 설정된 profile 페이지 접속 성공

30 서비스 빌드 (컴파일) 개발환경: 현재까지는 angular live server 환경에서 개발
백엔드 서버 클라이언트 개발을 위한 라이브 서버 배포환경: 개발 완료 후 메인 서버로 통합 운영 공용 서버로 이전 준비 서버명, 포트번호 고려

31 준비사항 Auth.service.ts 파일 수정 서버명칭, 포트번호 설정을 쉽게 하기 위한 준비 Full path 지정
@Injectable() export class AuthService { authToken: any; user: any; constructor(private { } registerUser(user){ let headers = new Headers(); headers.append('Content-Type','application/json'); let ep = this.prepEndpoint('users/register'); return this.http.post(ep, user,{headers: headers}) .map(res => res.json()); } 중략…. prepEndpoint(ep){ return ' // return ' Auth.service.ts 파일 수정 서버명칭, 포트번호 설정을 쉽게 하기 위한 준비 Full path 지정 공용서버로 옮기는 경우의 변경

32 준비사항 Auth.service.ts 파일 수정 다른 함수들도 패스 수정 authenticateUser(user){
let headers = new Headers(); headers.append('Content-Type','application/json'); let ep = this.prepEndpoint('users/authenticate'); return this.http.post(ep, user,{headers: headers}) .map(res => res.json()); } getProfile(){ this.loadToken(); headers.append('Authorization', this.authToken); let ep = this.prepEndpoint('users/profile'); return this.http.get(ep,{headers: headers})

33 서비스 빌드 (컴파일) 빌드 명령어 빌드를 수행하면 public 폴더에 클라이언트측 콘텐츠가 배포되며 서버코드와 직접 연동됨
> cd angular-src > ng build 빌드를 수행하면 public 폴더에 클라이언트측 콘텐츠가 배포되며 서버코드와 직접 연동됨 백엔드 서버 포트(3000)로 직접 연결 모든 서비스 동작

34 공용 서버로 업로드 Auth.service.ts 파일에서 필요사항 수정 후 빌드 서버에 업로드 및 서비스 실행
자신에게 할당된 포트번호 사용 서버에 업로드 및 서비스 실행 서버에 전체 프로젝트 폴더 업로드 필요시 서버 파일명 수정 > node app.js & 웹브라우저로 접속 테스트 로 접속 prepEndpoint(ep){ // return ' return ' }

35 과제 3. meanauthapp 서버에서 실행하기
지금까지 완성된 프로젝트를 isweb 서버의 자신의 계정 에 업로드, 실행하고 자신의 홈페이지 과제물 페이지에 링크하기 중간고사 실무과제에 포함


Download ppt "MEAN Stack Front to Back (MEANAuthApp)"

Similar presentations


Ads by Google