auth-guard.ts 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import { CanActivate, ExecutionContext, Injectable, ReflectMetadata } from '@nestjs/common';
  2. import { Reflector } from '@nestjs/core';
  3. import { GqlExecutionContext } from '@nestjs/graphql';
  4. import { Request, Response } from 'express';
  5. import { Permission } from 'shared/generated-types';
  6. import { ConfigService } from '../../config/config.service';
  7. import { Session } from '../../entity/session/session.entity';
  8. import { AuthService } from '../../service/providers/auth.service';
  9. import { extractAuthToken } from './extract-auth-token';
  10. import { REQUEST_CONTEXT_KEY, RequestContextService } from './request-context.service';
  11. import { setAuthToken } from './set-auth-token';
  12. export const PERMISSIONS_METADATA_KEY = '__permissions__';
  13. /**
  14. * Attatches metadata to the resolver defining which permissions are required to execute the
  15. * operation.
  16. *
  17. * @example
  18. * ```
  19. * @Allow(Permission.SuperAdmin)
  20. * @Query()
  21. * getAdministrators() {
  22. * // ...
  23. * }
  24. * ```
  25. */
  26. export const Allow = (...permissions: Permission[]) => ReflectMetadata(PERMISSIONS_METADATA_KEY, permissions);
  27. /**
  28. * A guard which checks for the existence of a valid session token in the request and if found,
  29. * attaches the current User entity to the request.
  30. */
  31. @Injectable()
  32. export class AuthGuard implements CanActivate {
  33. strategy: any;
  34. constructor(
  35. private reflector: Reflector,
  36. private configService: ConfigService,
  37. private authService: AuthService,
  38. private requestContextService: RequestContextService,
  39. ) {}
  40. async canActivate(context: ExecutionContext): Promise<boolean> {
  41. const ctx = GqlExecutionContext.create(context).getContext();
  42. const req: Request = ctx.req;
  43. const res: Response = ctx.res;
  44. const authDisabled = this.configService.authOptions.disableAuth;
  45. const permissions = this.reflector.get<Permission[]>(PERMISSIONS_METADATA_KEY, context.getHandler());
  46. const isPublic = !!permissions && permissions.includes(Permission.Public);
  47. const hasOwnerPermission = !!permissions && permissions.includes(Permission.Owner);
  48. const session = await this.getSession(req, res, hasOwnerPermission);
  49. const requestContext = await this.requestContextService.fromRequest(req, permissions, session);
  50. req[REQUEST_CONTEXT_KEY] = requestContext;
  51. if (authDisabled || !permissions || isPublic) {
  52. return true;
  53. } else {
  54. return requestContext.isAuthorized || requestContext.authorizedAsOwnerOnly;
  55. }
  56. }
  57. private async getSession(
  58. req: Request,
  59. res: Response,
  60. hasOwnerPermission: boolean,
  61. ): Promise<Session | undefined> {
  62. const authToken = extractAuthToken(req, this.configService.authOptions.tokenMethod);
  63. if (authToken) {
  64. return await this.authService.validateSession(authToken);
  65. } else if (hasOwnerPermission) {
  66. const session = await this.authService.createAnonymousSession();
  67. setAuthToken({
  68. authToken: session.token,
  69. rememberMe: true,
  70. authOptions: this.configService.authOptions,
  71. req,
  72. res,
  73. });
  74. return session;
  75. }
  76. }
  77. }