Nest에는 Guards라는 게 있다(뭐가 이렇게 많냐)
미들웨어와 비슷한 기능을 하지만, 미들웨어와는 다른 부분이 있는데 그 부분은 뒤에 다시 정리해보고자 한다.
Guards have a single responsibility. They determine whether a given request will be handled by the route handler or not, depending on certain conditions (like permissions, roles, ACLs, etc.) present at run-time. This is often referred to as authorization. Authorization (and its cousin, authentication, with which it usually collaborates) has typically been handled by middleware in traditional Express applications. Middleware is a fine choice for authentication, since things like token validation and attaching properties to the request object are not strongly connected with a particular route context (and its metadata). - nest 공식문서
요약하자면, Guards는 주어진 request에 대해 어떤 작업을 수행하는 데 주어진 조건에 따라 Route handler에 의해 처리될지 아닐지를 결정하게 한다는 것이다. request에 대해 이것을 진행시킬지 말지 여부를 결정하는 일종의 보호장치 처럼 이해하면 될 것 같다(이름부터가..).
그리고 이것은 위에 설명한 특징에 따라 인증Authorization에 많이 사용되는데, 주로 이와 같은 과정은 Middleware가 처리해왔으나 굳이 Guard를 쓰는 이유가 있다고 한다.
But middleware, by its nature, is dumb. It doesn't know which handler will be executed after calling the next() function. On the other hand, Guards have access to the ExecutionContext instance, and thus know exactly what's going to be executed next. They're designed, much like exception filters, pipes, and interceptors, to let you interpose processing logic at exactly the right point in the request/response cycle, and to do so declaratively. This helps keep your code DRY and declarative. - nest 공식문서
굳이 그렇다면 멀쩡한 Middleware를 두고 Guards를 쓰는지에 대한 nest의 대답이다. 이유는 Middleware는 멍청하기 때문이라는 것. 미들웨어는 next()의 다음에 route handler가 무슨 일을 하는지 알 수 없지만, Guards는 ExcutionContext 인스턴스에 접근해서 이를 알 수 있다는 이야기다. 이를 통해 코드를 더 선언적으로 유지할 수 있다는데...(아직은 잘 모르겠다)
일단은 핵심적으로 ExcutionContext에 Guards가 접근 가능하다!라는 것으로 Middleware와의 차이점 및 필요성을 정리해놓고 넘어가보자
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext) {
const getContext = GqlExecutionContext.create(context).getContext();
const user = getContext['user'];
if (!user) {
return false;
}
return true;
}
}
//적용예시
@Query((returns) => User)
@UseGuards(AuthGuard)
anyMethod() {
...
}
기능적 이해는 사용하면서 이해되었지만, 실질적으로 아직 딱 머릿속에 들어오지는 않는다. 다시 복습해야겠다.