본문 바로가기
Front-end Framework/Angular

[실전 어플리케이션 만들기] 7. RouterGuard 설정 및 Referrer URL 설정

by kellis 2020. 10. 20.

이 글에서는 권한이 없는 사용자가 url을 통해 페이지에 접근하려고 할 때, 접근을 제한하고 그에 따른 처리를 하도록 도와주는 RouteGuard를 설정해볼 것입니다. 또한 권한이 없어 로그인 페이지로 리다이렉트 되었을 때, 로그인 후에 처음 요청했던 페이지로 이동될 수 있도록 이전 페이지를 관리하는 코드를 함께 작성해 볼 것입니다.

 

 

1. RouterGuard 설정하기

 

권한이 없는 사용자가 권한이 필요한 특정 페이지로 접근했을 때, 라우팅되지 않도록 막아주는 역할을 하는 것이 RouterGuard입니다. 이 글에서는 로그인하지 않은 사용자가 마이페이지로 접근하려고 시도했을 때 로그인 페이지로 리다이렉트 되도록 구현해 볼 것입니다. 

 

먼저 core/service 아래에 auth-guard.ts 파일을 생성하여 아래와 같이 작성합니다. 

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(
    private store: Store<AppState>,
    private router: Router
  ) {}
  canActivate(): Observable<boolean> {
    return this.store.select('user').pipe(map(user => {
      if (user.isAuth) {
        return true;
      } else {
        this.router.navigateByUrl('/auth/loginForm');
        return false;
      }
    }));
  }
}

CanActivate를 구현하는 AuthGuard를 작성합니다. CanActivate를 구현할 경우 반드시 canActivate메서드를 오버라이드해야 하며, 이 메서드는 Observable을 반환합니다.

로그인 여부에 대한 정보는 스토어에 저장된 user 객체가 가지고 있고, 이 객체의 isAuth가 false인 경우 로그인페이지로 라우팅 되도록 하였습니다. 

작성한 AuthGuard를 특정 페이지 라우팅에 적용하는 방법은 간단합니다. 

 

[mypage-routing.module.ts]

const routes: Routes = [
  {
    path : '',
    component : MypageComponent,
    canActivate: [AuthGuard]
  }
];
 
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class MypageRoutingModule { }

2장에서 작성하였던 mypage-routing.module.ts를 일부 수정하였습니다. routes 정보에 canActivate 추가하고 AuthGuard를 지정해주면, '/mypage'로 라우팅 될 때 AuthGuard의 canActivate 메서드가 호출되게 됩니다. 

 


2. Referrer URL 관리

 

하지만 위의 코드는 단순히 로그인폼 페이지로만 이동되며, 로그인을 완료한 경우에 메인페이지로 이동되게 됩니다. 만약 사용자가 마이페이지를 접속하길 원해 로그인하였다면, 로그인의 결과 페이지는 마이페이지가 되어야 합니다. 

이를 위해 AuthGuard를 수정해 주도록 하겠습니다. 

 

[auth-guard.ts]

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(
    private store: Store<AppState>,
    private router: Router
  ) {}
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.store.select('user').pipe(map(user => {
      if (user.isAuth) {
        return true;
      } else {
        this.router.navigate(['/auth/loginForm', { referrerUrl: state.url }]);
        return false;
      }
    }));
  }
}

canActivate 메서드의 매개변수로 route와 state를 받습니다. 우리가 필요한 것은 바로 이 state 변수입니다. RouterSnapshot 타입인 state는 현재 페이지의 url 정보를 가지고 있습니다.

이 url 정보를 router.navigate에 인자로 함께 넣어주면 로그인 폼 컴포넌트로 이동될 때 이 값을 함께 넘겨줄 수 있습니다. 그러므로 로그인폼 컴포넌트 역시 이 url을 받아 사용할 수 있도록 수정되어야 합니다. 

 

[login-form.component.ts]

@Component({
  selector: 'app-login-form',
  templateUrl: './login-form.component.html',
  styleUrls: ['./login-form.component.css']
})
export class LoginFormComponent implements OnInit {
  hide;
   
  loginForm = this.fb.group({
    loginId: ['', Validators.required],
    passwd: ['', Validators.required]
  });
 
  referrerUrl: string;
 
  constructor(
    private fb: FormBuilder,
    private route: ActivatedRoute,
    private router: Router,
    private store: Store<AppState>
  ) {}
 
  ngOnInit(): void {
    this.referrerUrl = this.route.snapshot.paramMap.get('referrerUrl');
  }
 
 
  login() {
    const formValues = this.loginForm.value;
    if (this.loginForm.invalid) {
      alert('ID/PW를 입력해주세요');
      return false;
    }
    formValues['referrerUrl'] = this.referrerUrl;
 
    this.store.dispatch(new LogIn(formValues));
  }
}

생성자 메서드로 ActivatedRoute를 주입받아, 이 객체로부터 넘어온 url정보를 컴포넌트의 상태로 놓습니다. 폼이 서브밋될 때 이전 페이지로 리다이렉트 될 수 있도록, 폼 밸류에 referrerUrl로 페이지 url을 넣어줍니다. 이제 실제로 로그인이 성공했을 때 메인 페이지로 이동되는 것이 아니라, referrerUrl에 저장된 url로 이동되면 되는 것입니다. 

 

[auth.affects.ts]

@Effect({dispatch: false})
LogInSuccess: Observable<any> = this.actions.pipe(
    ofType(AuthActionTypes.LOGIN_SUCCESS),
    tap((user) => {
      this.router.navigateByUrl(user.payload.referrerUrl);
    })
);

auth.effects.ts  파일을 위와 같이 수정해 주고 나면 referrer URL 설정이 모두 끝나게 됩니다.

 


Conclusions

 

지금까지 로그인 인증 어플리케이션을 작성해 보았습니다. 앵귤러의 인메모리 디비 서비스를 활용하여, 별도의 서버 프로그램 없이 클라이언트 프로그램을 만드는 예제였습니다. 

 

 

[reference]

Auth 예제 : https://mherman.org/blog/authentication-in-angular-with-ngrx/#route-guard-1

댓글