• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

AuthGuard에 관한 질문

22.03.11 02:59 작성 조회수 346

0

제로초님 안녕하세요. 

AuthGuard를 이용해 로그인 처리를 하고있습니다. 세션 쿠키 방식을 사용하고 있구요.

로그인 방식이

1.  리퀘스트에 쿠키가 있으면 =>  쿠키로 세션을 불러와서 안에 들어가있는 user id를 가져와서 디비에서 검색후 로그인

2. 리퀘스트에 쿠키가 없으면 => 디비에서 id와 password를 검색하고 있을 시 세션에 저장하고 로그인. 없으면 UnauthorizedException

이렇게 되는 걸로 파악했는데요.

리퀘스트에 쿠키가 있고 세션에도 저장된 게 있지만 디비에서 유저가 지워졌을 경우, 1번 방식에서 user id가 없기 때문에, 그냥 500 에러가 발생하고 끝나는데요. 

저는 이 때, 다시  2번 방식으로 돌리는 플로우로 가고 싶습니다.(쿠키 세션으로 불러지는 정보가 없을 경우, 디비에서 id와 password를 가지고 검색 후 처리)
그래서 막연히 LocalAuthGuard 에 null 값을 주고 실행해 봤는데, 아무 동작도 하지 않았습니다. 

어떻게하면 좋을지 조언을 듣고 싶습니다.

```ts

local-auth.guard.ts
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
async canActivate(context: ExecutionContext): Promise<boolean> {
 
if (context) {
const can = await super.canActivate(context);
if (can) {
const request = context.switchToHttp().getRequest();
console.log('쿠키 사용해서 로그인 : ', request);

await super.logIn(request);
}
}

return true;
}
}

```
```ts
local.strategy.ts

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({ usernameField: 'email', passwordField: 'password' });
}

async validate(email: string, password: string, done: CallableFunction) {
const user = await this.authService.validateUser(email, password);
 

if (!user) {
throw new UnauthorizedException();
}
return done(null, user);
}
}

```

```ts

local.serializer.ts

@Injectable()
export class LocalSerializer extends PassportSerializer {
constructor(
private readonly authService: AuthService,
private readonly localStrategy: LocalStrategy,
private readonly localAuthGuard: LocalAuthGuard,
private readonly reLocalAuthGuard: ReLocalAuthGuard,
@InjectRepository(HpMasterUserRepository, 'homepage-db')
private userRepository: UserRepository,
) {
super();
}

serializeUser(User: User, done: CallableFunction) {

done(null, user.UserId);
}

async deserializeUser(userId: number, done: CallableFunction) {
try {

const user =
await this.userRepository.selectHpMasterUserById(
userId,
);

if (hpMasterUser) {
done(null, hpMasterUser.userId); // req.user
}
await this.localAuthGuard.canActivate(null);
// this.reLocalAuthGuard.canActivate(null);
} catch (err) {

// throw new UnauthorizedException();
done(err);
}
}
}

```

```ts

auth.service.ts

@Injectable()
export class AuthService {
constructor(private userService: UserService) {}

async validateUser(email: string, password: string) {
const user = await this.userService.masterUserLogin(email, password);

if (!user) {
return null;
} else if (user) {
const { password, ...userWithOutPassword } = user;

return userWithOutPassword;
}

return null;
}
}

```

답변 1

답변을 작성해보세요.

0

뭔가 이상한데요. 로그인 시에는 아예 쿠키를 참조하지 않습니다. 쿠키가 들어있어도 쓰질 않습니다. 어떤 부분을 보시고 세션을 쓴다고 생각하신건가요?

우선 제가 실험해본 것은 db에서 id를 지우고 나서 어떻게 되나를 실험해본 것인데, 제가했던 순서는

1. 존재하는 아이디로 로그인 : 이 때, 쿠키, 세션 만들어짐. 로그인 됨

2.  db에서 1에서 로그인했던 아이디 삭제

3. 다시 1의 아이디로 로그인 : deserealizeUser 부분에서 에러가 남.(userId를 못읽음)
 - 이 때는 authService의 validateUser까지 가지 않음
```

response
{
"statusCode": 500,
"message": "Internal server error"
}

```


4. 쿠키를 지우고 1의 아이디로 로그인 : authService의 validateUser까지 가서 findOne 한것을 확인.

```

response

{
"success": false,
"code": 401,
"data": {
"statusCode": 401,
"message": "Unauthorized"
}
}

```

이런 결과가 나와서 리퀘스트에 쿠키가 있을 경우와 없을 경우가 다른 프로세스를 탄다고 파악했습니다.

실험 방법이 잘못되었습니다. 쿠키가 유효하면 서버는 당연히 로그인되어있다고 생각했는데 db에서 아이디를 지워버리면 서버가 에러가 날 수밖에 없죠. deserializeUser는 로그인 성공 후에만 호출되는 함수입니다.

쿠키를 지우면 서버는 로그인 안 한 상태라고 생각하니까 일반적인 로그인 프로세스를 타는 겁니다.

애초에 서버를 통하지 않고 db가 지워지는 상황이 존재해서는 안 됩니다.

관리자가 유저 아이디를 삭제했는데, 유저가 자기 아이디가 삭제된 지 모르고 로그인 하려고 할 때를 가정해보았습니다,, 이럴 때는 쿠키가 있어도 db에서 검색하는 게 필요하지 않을까요?

그런 케이스라면 done(err) 대신 throw new UnauthorizedException()을 던지고 401인 경우 프론트에서 로그인창으로 리다이렉트해주면 되겠네요.