티스토리 뷰
Angular : Email Client - 1-6. 인증모듈작성 - 비동기 검증로직을 사용한 username 중복 확인 및 Password Validator 작성
Korean Eagle 2020. 6. 23. 16:521. 이 포스트는 Email Client를 작성하는 시리즈의 일부이다
1-0 이 포스트는 동기, 비동기 검증로직을 모두 생성한다.
1-0-1 비동기 검증로직은 여기서 처음 작성하는 내용이므로 Angular 섹션에 없다.
1-1 여기서는 두 개의 비밀번호가 일치하는지를 확인하는 검증 로직과
1-2 사용을 원하는 Username이 이미 사용중인지를 확인하는 검증 로직을 작성한다.
1-3 검증로직은 범용이 가능하도록 분리하여 작성한다. 범용 검증로직에 대한 내용은 아래 링크를 참조한다.
Angular : Password Validator 구현 사용자 정의 Validator 2
1. 이번 포스트는 지난 포스트의 사용자 정의 검증로직을 좀 더 범용적으로 사용할 수 있도록 변경한다. 1-1 지난 포스트의 연속이므로 이전 포스트를 읽는 게 좋다. 2. 범용로직을 작성한다. 2-0 ��
kogle.tistory.com
2. 두 개의 비밀번호가 일치하는지 여부 작성
2-1 AuthValidators 클래스를 생성한다.
2-2 아래처럼 코드를 작성한다. 간단한 동기식 비밀번호 검증 로직이다.
import { AbstractControl } from '@angular/forms';
export class AuthValidators {
static checkPasswordMatch(param1: string, param2: string) {
return (form: AbstractControl) => {
const pass1 = form.value[param1]
const pass2 = form.value[param2]
if (pass1 !== pass2) {
return { notMatch: true }
}
return null
}
}
}
2-3 이제 sign up 컴포넌트에서 사용하도록 하자
2-3-1 validator를 group의 두 번째 인자로 사용했음을 주의한다.
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { AuthValidators } from '../validators/auth-validators';
@Component({
selector: 'app-sign-up',
templateUrl: './sign-up.component.html',
styleUrls: ['./sign-up.component.css'],
})
export class SignUpComponent implements OnInit {
registrationGroup: FormGroup;
constructor(
private formBuilder: FormBuilder
) {}
ngOnInit(): void {
this.registrationGroup = this.formBuilder.group(
{
username: [
'',
[
Validators.required,
Validators.minLength(4),
Validators.maxLength(10),
],
],
password: [
'',
[
Validators.required,
Validators.minLength(4),
Validators.maxLength(10),
],
],
passwordConfirmation: [
'',
[
Validators.required,
Validators.minLength(4),
Validators.maxLength(10),
],
],
},
{
validators: AuthValidators.checkPasswordMatch(
'password',
'passwordConfirmation'
),
}
);
}
}
2-4 결과를 확인해 본다. - 비밀번호가 다를 경우 notMatched가 설정된다.
3. 이번에는 비동기식 검증이다. 지정한 username이 사용중인지를 확인하는 경우다.
3-0 서비에 사용자확인은 post 방식으로 https://api.angular-email.com/auth/username url로 요청한다.
3-1 보낼 데이터는 { username: string } 방식으로 전송한다.
3-2 auth Service의 코드이다. 중요한 부분은 checkDuplication이 추가된 부분이다.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject } from 'rxjs';
import { tap } from 'rxjs/operators'
import { AuthCredential } from './auth-responses';
@Injectable({
providedIn: 'root'
})
export class AuthService {
signedIn$ = new BehaviorSubject(null)
username: string = ''
url = 'https://api.angular-email.com/auth'
constructor(private http: HttpClient) { }
signedIn(): Observable<SignedInResponse> {
return this.http.get<SignedInResponse>(`${this.url}/signedIn`).pipe(
tap((response: SignedInResponse)=> {
this.username = response.username
this.signedIn$.next(response.authenticated)
})
)
}
signUp(crediential: AuthCredential) {
return this.http.post(`${this.url}/signup`, crediential)
}
checkDuplication(username: string) {
console.log(username);
return this.http.post(`${this.url}/username`, { username })
}
}
interface SignedInResponse {
authenticated: boolean,
username: string
}
3-3 결과 데이터의 포멧은 일관적이지 않는데,
3-3-1 실패하면 { username: string } 이 반환되고,
3-3-2 성공하면 { available: boolean } 이 반환된다.
3-3-3 좀 더 짜증나는 부분은 성공하면 200, 실패하면 422번 에러를 보낸다.
3-3-4 따라서 pipe에서도 성공과 실패를 구분해서 가공을 해야 한다.
3-4 AuthValidators에 static 메소드를 하나 더 추가하는데, 이번에는 사용할 서비스를 인자로 받아야 한다.
3-4-1 서비스를 받지 않으면 자체적으로 구현해야 하는데, 그러면 static으로 구현할 수 없다.
3-4-2 일반 클래스를 정의하고 생성자에서 서비스를 받아 사용하고 이 클래스 자체도 @injectable로 생성해야 한다.
3-4-3 코드 재활용과 독립성에 유리하게 보이지만 생각해보면 어차피 서비스 메소드에 따라 검증코드를 바꿔야 한다.
3-4-4 그래서 나는 static을 선호한다.
3-5 소스코드를 보면 동기식과 비슷하게 작성되어 있다. 함수를 리턴하는 것이고 반환값만 Observable이면 된다.
3-5-1 사실 guard와 거의 동일하고 할 수 있다.
3-5-2 결과를 받아 pipe에서 map으로 들어가는 경우는 정상적인 200번 리턴이고 422는 catchError로 넘어간다.
3-5-3 422일 때 usename이 있는 경우는 정상적인 서버 반환데이터이고 없으면 네트워크 오류로 처리했다.
3-5-4 of는 RxJS 생성 operator 중에 하나이다. catchError의 경우 데이터를 변환해야 하므로 사용했다.
3-5-5 정상의 경우 null 반환이 가능한 이유는 반환 타입이 AsyncValidatorFn | AsyncValidatorFn[] | null) 기 때문이다.
import { AbstractControl } from '@angular/forms';
import { AuthService } from '../auth.service';
import { map, catchError } from 'rxjs/operators';
import { of, Observable } from 'rxjs';
export class AuthValidators {
static checkPasswordMatch(param1: string, param2: string) {
return (form: AbstractControl) => {
const pass1 = form.value[param1]
const pass2 = form.value[param2]
if (pass1 !== pass2) {
return { notMatch: true }
}
return null
}
}
static checkUniqueUsername(authService: AuthService) {
return (control: AbstractControl): Observable<any> => {
return authService.checkDuplication(control.value).pipe(
map(value => {
return null
}),
catchError(err => {
console.log(err);
if (err.error.username) {
return of({ duplication: true })
}
return of({noInternet: true})
})
)
}
}
}
3-6 사용하는 부분에서도 service를 받아 넘겨주도록 코드를 수정해야 한다.
3-6-1 생성자에서 authSerivce를 주입받아서 username FormControl의 세번째 인자함수의 인자로 넘겨준다.
3-6-2 이것을 받은 함수는 단순히 러턴 함수를 생성하는 기능을 하고 적절하게 세팅한 후 Observable을 돌려준다.
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { AuthValidators } from '../validators/auth-validators';
import { AuthService } from '../auth.service';
@Component({
selector: 'app-sign-up',
templateUrl: './sign-up.component.html',
styleUrls: ['./sign-up.component.css'],
})
export class SignUpComponent implements OnInit {
registrationGroup: FormGroup;
constructor(
private formBuilder: FormBuilder,
private authService: AuthService
) {}
ngOnInit(): void {
this.registrationGroup = this.formBuilder.group(
{
username: [
'',
[
Validators.required,
Validators.minLength(4),
Validators.maxLength(20),
], AuthValidators.checkUniqueUsername(this.authService)
],
password: [
'',
[
Validators.required,
Validators.minLength(4),
Validators.maxLength(20),
],
],
passwordConfirmation: [
'',
[
Validators.required,
Validators.minLength(4),
Validators.maxLength(20),
],
],
},
{
validators: AuthValidators.checkPasswordMatch(
'password',
'passwordConfirmation'
),
}
);
}
}
3-7 결과화면
3-7-1 이전에 piilseong 이라는 username을 만든 적이 있어서 중복이라고 나온다.
4. 이제 form에 대한 검증 처리가 끝났으니 검증이 완료되었을 때만 버튼이 활성화 되도록 변경한다.
4-1 리셋 버튼도 추가하여 폼에 입력된 데이터도 초기화 한다.
4-2 가입 화면
<h1 class="my-5">Create an Account</h1>
<form class="col-sm-8" [formGroup]="registrationGroup">
<div class="form-group">
<label class="form-label" for="username">Username</label>
<input id="username" class="form-control" type="text" formControlName="username">
</div>
<div class="form-group">
<label class="form-label" for="password">Password</label>
<input id="password" class="form-control" type="password" formControlName="password">
</div>
<div class="form-group">
<label class="form-label" for="passwordConfirmation">Password Confirmation</label>
<input id="passwordConfirmation" class="form-control" type="password" formControlName="passwordConfirmation">
</div>
<div class="my-4">
<button type="submit" class="btn btn-secondary mr-2" [disabled]="!registrationGroup.valid">Submit</button>
<button type="reset" class="btn btn-warning">Reset</button>
</div>
</form>
<hr>
<div>
valid : {{ registrationGroup.valid }}<br>
errors : {{ registrationGroup.errors | json }}<br>
username errors: {{ registrationGroup.controls.username.errors | json }}
</div>
4-3 로그인 화면
<h1 class="my-5">Log In</h1>
<form class="col-sm-8" [formGroup]="loginGroup">
<div class="form-group">
<label class="form-label" for="username">Username</label>
<input id="username" class="form-control" type="text" formControlName="username">
</div>
<div class="form-group">
<label class="form-label" for="password">Password</label>
<input id="password" class="form-control" type="password" formControlName="password">
</div>
<div class="my-3">
<button type="submit" class="btn btn-secondary mr-2" [disabled]="!loginGroup.valid">Submit</button>
<button type="reset" class="btn btn-warning">Reset</button>
</div>
</form>
'Demos > Email Client' 카테고리의 다른 글
Angular : Email Client - 1-8. 인증모듈작성 - 가입하기와 로그인 로직 작성하기 (0) | 2020.06.23 |
---|---|
Angular : Email Client - 1-7. 인증모듈작성 - 검증 에러 메시지 보여주기 (0) | 2020.06.23 |
Angular : Email Client - 1-5. 인증모듈작성 - Sign up, Sign in Template과 Form Control 작성하기 (0) | 2020.06.22 |
Angular : Email Client - 1-4. 인증모듈작성 - email 모듈 guard 작성하기 (0) | 2020.06.22 |
Angular : Email Client - 1-3. 인증모듈작성 - 라우팅 설정하기 (0) | 2020.06.22 |
- Total
- Today
- Yesterday
- 도커 개발환경 참고
- AWS ARN 구조
- Immuability에 관한 설명
- 자바스크립트 멀티 비동기 함수 호출 참고
- WSDL 참고
- SOAP 컨슈머 참고
- MySql dump 사용법
- AWS Lambda with Addon
- NFC 드라이버 linux 설치
- electron IPC
- mifare classic 강의
- go module 관련 상세한 정보
- C 메모리 찍어보기
- C++ Addon 마이그레이션
- JAX WS Header 관련 stackoverflow
- SOAP Custom Header 설정 참고
- SOAP Custom Header
- SOAP BindingProvider
- dispatcher 사용하여 설정
- vagrant kvm으로 사용하기
- git fork, pull request to the …
- vagrant libvirt bridge network
- python, js의 async, await의 차이
- go JSON struct 생성
- Netflix Kinesis 활용 분석
- docker credential problem
- private subnet에서 outbound IP 확…
- 안드로이드 coroutine
- kotlin with, apply, also 등
- 안드로이드 초기로딩이 안되는 경우
- navigation 데이터 보내기
- 레이스 컨디션 navController
- raylib
- login
- hibernate
- 상속
- 스프링
- 외부파일
- XML
- 스프링부트
- WebMvc
- 설정하기
- Spring Security
- form
- mapping
- 자바
- 하이버네이트
- one-to-one
- Validation
- one-to-many
- 매핑
- Security
- 로그인
- spring boot
- Many-To-Many
- RestTemplate
- 설정
- crud
- Spring
- Angular
- jsp
- MYSQL
- Rest