문서를 보면 passport-local을 사용할때와 passport-jwt를 사용할때 함수형태가 다른것을 볼수있다.
async validate(username: string, password: string) // passport-local
async validate(payload: any) // passport-jwt
@nestjs/passport는 passport.js를 nestjs로 활용할수 있도록 래핑한 모듈이다.
어떻게 래핑이 되어있는가는 이 코드를 확인해보면 알수있다
export function PassportStrategy<T extends Type<any> = any>
모듈에서 import하여 사용하는 PassportStrategy는 함수이다.
어떻게 extends를 하냐 라고 한다면, 11번째 라인의 MixinStrategy를 리턴하는 함수이기때문이다.
abstract class MixinStrategy extends Strategy {
abstract validate(...args: any[]): any;
// ...
}
Generic타입인 Strategy를 확장하여 구현한 MixinStrategy는 validate가 abstract이기 때문에 무조건 구현해야한다.
For the local-strategy, Passport expects a
validate()
method with the following signature:validate(username: string, password:string): any
.
@nestjs/passport문서에 명시된 내용인데, passport의 local-strategy 문서랑 함께 보면 왜 validate가 저런 형태를 띄는지 알수있다.
passport.use(new LocalStrategy(
function(username, password, done) {
...
done( ... )
}
))
LocalStrategy는 function에 username과 password를 받을것을 예상하고있다.
validate함수가 LocalStrategy나 JwtStrategy가 다른이유는 각 Strategy 별로 값이 다를거라 예상하기 떄문이다.
실제로 passport.strategy.ts파일을 더 분석해보면 더 명확히 알수있다.
MixinStrategy constructor를 확인해보자
constructor(...args: any[]) {
const callback = async (...params: any[]) => {
const done = params[params.length - 1]; // strategy의 콜백함수 추출
try {
const validateResult = await this.validate(...params);
if (Array.isArray(validateResult)) {
done(null, ...validateResult); // 응답이 배열인경우 spread done
} else {
done(null, validateResult); // 배열이 아니고 값은 있는경우
}
} catch (err) {
done(err, null);
}
};
// ...
super(...args, callback);
// ...
}
핵심적인 부분만 가져와봤다.
callback이란 함수 하나를 정의하고있다.
이 callback함수의 역할은 무엇일까?
Passport Strategy들은 아래와같은 형태를 사용한다.
Streategy( function ( ...params, done) { ... }
마지막은 callback 함수인 done을 쓰고 앞에 나머지값은 파라미터로 생각하면된다.
passport-local의 경우 username, password를 순서대로 내보내는 코드를 작성해두었기 때문에 어떤 Strategy냐의 따라 달라진다는것을 유추할수있다.
PassportStrategy는 validate함수를 구현하고, validate함수의 파라미터는 각각 passport strategy를 확인하여 어떤 값이 전달되는지 확인할수있다