MEAN Stack Front to Back (MEANAuthApp) 6. Register Component, Validation & Flash messages 7. Auth Service & User Registration
목차 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
6. Register components Register components Validation Flash messages
Home component home/home.component.html Register 버튼 Login 버튼 <div class="jumbotron text-center"> <h1>MEAN Authentication App</h1> <p class="lead">Welcome to our custom MEAN authentication app</p> <div> <a class="btn btn-primary" [routerLink]="['/register']">Register</a> <a class="btn btn-default" [routerLink]="['/login']">Login</a> </div> </div> <div class="row"> <div class="col-md-4"> <h3>Express Backend</h3> <p>A rock solid Node.js/Express server using Mongoose to organize models and query the database.</p> <h3>Angular/CLI</h3> <p>Angular/CLI to generate components, services and more. Local dev server and easy compilation</p> <h3>JWT Tokens</h3> <p>Full featured authentication using JSON web tokens. Login and store user data</p> Register 버튼 Login 버튼 메인 페이지 컨텐츠 작성
Home component
Register component Register/register.component.ts 사용자 등록 페이지에서는 import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-register', templateUrl: './register.component.html', styleUrls: ['./register.component.css'] }) export class RegisterComponent implements OnInit { name: string; username: string; email: string; password: string; constructor() { } ngOnInit() { } onRegisterSubmit(){ const user = { name: this.name, email: this.email, username: this.username, password: this.password } } 사용자 등록 페이지에서는 4개의 사용자 입력정보 사용
Register component Register/register.component.html 사용자 등록 페이지 UI <h2 class="page-header">Register</h2> <form (submit)="onRegisterSubmit()"> <div class="form-group"> <label> Name </label> <input type="text" [(ngModel)]="name" name="name" class="form-control"> </div> <label> Username </label> <input type="text" [(ngModel)]="username" name="username" class="form-control"> <label> Email </label> <input type="text" [(ngModel)]="email" name="email" class="form-control"> <label> Password </label> <input type="password" [(ngModel)]="password" name="password" class="form-control"> <input type="submit" class="btn btn-primary" value="Submit"> </form> Submit 버튼이 눌리면 onRegisterSubmit() 함수가 실행됨 사용자 입력값을 ngModel로 연결 2-way binding 제공
Register component App.module.ts 에 FormsModule 추가 필요 import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule, Routes } from '@angular/router'; 중략 @NgModule({ imports: [ BrowserModule, FormsModule, RouterModule.forRoot(appRoutes) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } 사용자의 폼 입력을 다루는 모듈을 import하여 app.module.ts에 등록시킴
Register component
사용자 입력값 검증 추가 사용자 입력값이 있는지, 이메일주소 포맷이 맞는지 검 증하는 서비스 추가 서비스 생성 Angular-src/src/app/services 폴더 생성 위 폴더로 이동 Validate라는 서비스 생성 > ng g service validate
사용자 입력값 검증 추가 App/services 폴더에 두개의 파일 생성 이렇게 생성된 서비스는 app.module.ts 에 자동적으로 추가되지 않아 직접 추가해야 함
사용자 입력값 검증 추가 App.module.ts에 서비스 등록 다음 내용 추가 중략 import { ValidateService } from './services/validate.service'; providers: [ValidateService],
사용자 입력값 검증 추가 validate.service.ts 파일 수정 import { Injectable } from '@angular/core'; @Injectable() export class ValidateService { constructor() { } validateRegister(user) { if(user.name == undefined || user.email == undefined || user.username == undefined || user.password == undefined) { return false; } else { return true; } } validateEmail(email){ var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@ ((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return re.test(email); } 검증 관련 서비스 함수 2개를 등록 4개의 사용자 입력값 모두를 입력해야 함 이메일주소의 유효성을 검증하는 코드 구글 검색: javascript validate email
register.component.ts 파일 수정 import { Component, OnInit } from '@angular/core'; import { ValidateService } from '../../services/validate.service'; @Component({ selector: 'app-register', templateUrl: './register.component.html', styleUrls: ['./register.component.css'] }) export class RegisterComponent implements OnInit { name: string; username: string; email: string; password: string; constructor(private validateService: ValidateService) { } ngOnInit() { } 컴포넌트에서 서비스를 등록 onRegisterSubmit(){ const user = { name: this.name, email: this.email, username: this.username, password: this.password } // Required Fields if(!this.validateService.validateRegister(user)){ console.log('Please fill in all fields'); return false; // Validate Email if(!this.validateService.validateEmail(user.email)){ console.log('Please use a valid email'); } } 서비스 함수를 이용
Validation Test 4개의 정보를 모두 입력해야 등록 가능 유효한 이메일주소를 입력해야 에러가 발생한 경우 브라우저 콘솔에 표시
Flash Message 기능 추가 목적 Flash message 패키지 설치 Angular-src 폴더에서 설치 (front-end에 적용) npm install angular2-flash-messages --save Angular-src/package.json 파일에 적용 확인
Flash Message 기능 추가 App.module.ts 에 적용 import { ValidateService } from './services/validate.service'; import { FlashMessagesModule } from 'angular2-flash-messages'; 중략 imports: [ BrowserModule, FormsModule, RouterModule.forRoot(appRoutes), FlashMessagesModule ],
Flash Message 기능 추가 App.component.html 파일 수정 <app-navbar></app-navbar> <div class="container"> <flash-messages></flash-messages> <router-outlet></router-outlet> </div> Flash message는 메뉴바 아래, 메인 콘텐츠 위에 표시함
Flash Message 기능 추가 Register.component.ts 파일 수정 import { Component, OnInit } from '@angular/core'; import { ValidateService } from '../../services/validate.service'; import { FlashMessagesService } from 'angular2-flash-messages'; 중략 constructor(private validateService: ValidateService, private flashMessage: FlashMessagesService) { } // Required Fields if(!this.validateService.validateRegister(user)){ this.flashMessage.show('Please fill in all fields', {cssClass: 'alert-danger', timeout: 3000}); return false; } // Validate Email if(!this.validateService.validateEmail(user.email)){ this.flashMessage.show('Please use a valid email', {cssClass: 'alert-danger', timeout: 3000}); } }
Flash Message 기능 추가
7. Auth Service & User Registration
사용자 등록시 DB에 저장 새로운 auth service 생성 Angular-src/src/app/services 폴더로 이동 > ng g service auth 기능 - 사용자 등록시 서버의 Backend에 연결하여 사용자 정보를 전송 - 서버의 응답결과를 받아옴
사용자 등록시 DB에 저장 Auth.service.ts 파일 수정 import { Injectable } from '@angular/core'; import { Http, Headers } from '@angular/http'; import 'rxjs/add/operator/map'; @Injectable() export class AuthService { authToken: any; user: any; constructor(private http: Http) { } registerUser(user){ let headers = new Headers(); headers.append('Content-Type', 'application/json'); return this.http.post('http://localhost:3000/users/register', user, {headers: headers}) .map(res => res.json()); } } Http 서비스를 이용할 준비 Headers 모듈 사용 준비 Rxjs 사용 준비 인증토큰, 사용자정보 변수 선언 Http 서비스를 등록 Http 서비스로 사용자 정보를 전송 Observable을 리턴
AngularJS에서의 Http 서비스 AngularJS에서 사용하는 AJAX API
Reactive Programming Reactive Programming이란? Reactive programming is programming with asynchronous data streams. An amazing toolbox of functions to combine, create and filter any of those streams.
ReactiveX ReactiveX http://reactivex.io/ ReactiveX is a library for composing asynchronous and event- based programs by using observable sequences. ReactiveX provides a collection of operators with which you can filter, select, transform, combine, and compose Observables. https://github.com/ReactiveX/rxjs http://reactivex.io/rxjs/
Observables, observer, subscribe An Observer Subscribes to an Observable The observer reacts to whatever item or sequence of items the Observable emits
사용자 등록시 DB에 저장 참고: routes/users.js (Backend server의 응답) 사용자 입력값으로 // Register router.post('/register', (req, res, next) => { let newUser = new User({ name: req.body.name, email: req.body.email, username: req.body.username, password: req.body.password }); User.addUser(newUser, (err, user)=>{ if(err) { res.json({success: false, msg: 'Failed to register user'}); } else { res.json({success: true, msg: 'User registered'}); } }); 사용자 입력값으로 newUser 객체 생성 mongoDB에 저장
사용자 등록시 DB에 저장 App.module.ts 파일에서 auth service 등록 필요한 모듈 import import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpModule } from '@angular/http'; 중략 import { ValidateService } from './services/validate.service'; import { AuthService } from './services/auth.service'; import { FlashMessagesModule } from 'angular2-flash-messages'; imports: [ BrowserModule, FormsModule, HttpModule, RouterModule.forRoot(appRoutes), FlashMessagesModule ], providers: [ValidateService, AuthService], 필요한 모듈 import 필요한 서비스 import 모듈 등록 서비스 등록
사용자 등록시 DB에 저장 register.component.ts 파일 수정 필요한 서비스 import 서비스 등록 import { Component, OnInit } from '@angular/core'; import { ValidateService } from '../../services/validate.service'; import { AuthService } from '../../services/auth.service'; import { FlashMessagesService } from 'angular2-flash-messages'; import { Router } from '@angular/router'; 중략 constructor( private validateService: ValidateService, private flashMessage: FlashMessagesService, private authService: AuthService, private router: Router ) { } // Validate Email if(!this.validateService.validateEmail(user.email)){ this.flashMessage.show('Please use a valid email', {cssClass: 'alert-danger', timeout: 3000}); return false; } // Register User this.authService.registerUser(user).subscribe(data => { if(data.success) { this.flashMessage.show('You are now registered and can log in', {cssClass: 'alert-success', timeout: 3000}); this.router.navigate(['/login']); } else { this.flashMessage.show('Something went wrong', {cssClass: 'alert-danger', timeout: 3000}); this.router.navigate(['/register']); } }); register.component.ts 파일 수정 필요한 서비스 import Router서비스는 페이지 리다이렉트에 사용 서비스 등록 서버의 응답을 받아서 처리 Subscribe 메서드 이용 등록 성공시 로그인 페이지로 리다이렉트 등록 실패시 등록 페이지로 리다이렉트
테스트 사용자 등록 성공 로그인 페이지로 리다이렉트 DB에 저장 확인