mirror of
https://github.com/immich-app/immich.git
synced 2024-12-28 22:51:59 +00:00
refactor(server): merge auth guards to authentication guard (#877)
This commit is contained in:
parent
9614da6238
commit
443c842723
9 changed files with 46 additions and 63 deletions
|
@ -6,7 +6,6 @@ import {
|
|||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
UseGuards,
|
||||
ValidationPipe,
|
||||
ParseUUIDPipe,
|
||||
Put,
|
||||
|
@ -15,7 +14,7 @@ import {
|
|||
import { ParseMeUUIDPipe } from '../validation/parse-me-uuid-pipe';
|
||||
import { AlbumService } from './album.service';
|
||||
import { CreateAlbumDto } from './dto/create-album.dto';
|
||||
import { JwtAuthGuard } from '../../modules/immich-jwt/guards/jwt-auth.guard';
|
||||
import { Authenticated } from '../../decorators/authenticated.decorator';
|
||||
import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator';
|
||||
import { AddAssetsDto } from './dto/add-assets.dto';
|
||||
import { AddUsersDto } from './dto/add-users.dto';
|
||||
|
@ -27,7 +26,7 @@ import { AlbumResponseDto } from './response-dto/album-response.dto';
|
|||
import { AlbumCountResponseDto } from './response-dto/album-count-response.dto';
|
||||
|
||||
// TODO might be worth creating a AlbumParamsDto that validates `albumId` instead of using the pipe.
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Authenticated()
|
||||
@ApiBearerAuth()
|
||||
@ApiTags('Album')
|
||||
@Controller('album')
|
||||
|
|
|
@ -3,7 +3,6 @@ import {
|
|||
Post,
|
||||
UseInterceptors,
|
||||
Body,
|
||||
UseGuards,
|
||||
Get,
|
||||
Param,
|
||||
ValidationPipe,
|
||||
|
@ -17,7 +16,7 @@ import {
|
|||
UploadedFile,
|
||||
Header,
|
||||
} from '@nestjs/common';
|
||||
import { JwtAuthGuard } from '../../modules/immich-jwt/guards/jwt-auth.guard';
|
||||
import { Authenticated } from '../../decorators/authenticated.decorator';
|
||||
import { AssetService } from './asset.service';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import { assetUploadOption } from '../../config/asset-upload.config';
|
||||
|
@ -52,7 +51,7 @@ import { AssetCountByUserIdResponseDto } from './response-dto/asset-count-by-use
|
|||
import { CheckExistingAssetsDto } from './dto/check-existing-assets.dto';
|
||||
import { CheckExistingAssetsResponseDto } from './response-dto/check-existing-assets-response.dto';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Authenticated()
|
||||
@ApiBearerAuth()
|
||||
@ApiTags('Asset')
|
||||
@Controller('asset')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Body, Controller, Post, Res, UseGuards, ValidationPipe, Ip } from '@nestjs/common';
|
||||
import { Body, Controller, Post, Res, ValidationPipe, Ip } from '@nestjs/common';
|
||||
import { ApiBadRequestResponse, ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||
import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator';
|
||||
import { JwtAuthGuard } from '../../modules/immich-jwt/guards/jwt-auth.guard';
|
||||
import { Authenticated } from '../../decorators/authenticated.decorator';
|
||||
import { AuthService } from './auth.service';
|
||||
import { LoginCredentialDto } from './dto/login-credential.dto';
|
||||
import { LoginResponseDto } from './response-dto/login-response.dto';
|
||||
|
@ -42,7 +42,7 @@ export class AuthController {
|
|||
return await this.authService.adminSignUp(signUpCredential);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Authenticated()
|
||||
@ApiBearerAuth()
|
||||
@Post('/validateToken')
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { Controller, Post, Body, Patch, UseGuards, ValidationPipe } from '@nestjs/common';
|
||||
import { Controller, Post, Body, Patch, ValidationPipe } from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||
import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator';
|
||||
import { JwtAuthGuard } from '../../modules/immich-jwt/guards/jwt-auth.guard';
|
||||
import { Authenticated } from '../../decorators/authenticated.decorator';
|
||||
import { DeviceInfoService } from './device-info.service';
|
||||
import { CreateDeviceInfoDto } from './dto/create-device-info.dto';
|
||||
import { UpdateDeviceInfoDto } from './dto/update-device-info.dto';
|
||||
import { DeviceInfoResponseDto } from './response-dto/create-device-info-response.dto';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Authenticated()
|
||||
@ApiBearerAuth()
|
||||
@ApiTags('Device Info')
|
||||
@Controller('device-info')
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import { Controller, Get, Body, UseGuards, ValidationPipe, Put, Param } from '@nestjs/common';
|
||||
import { Controller, Get, Body, ValidationPipe, Put, Param } from '@nestjs/common';
|
||||
import { JobService } from './job.service';
|
||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard } from '../../modules/immich-jwt/guards/jwt-auth.guard';
|
||||
import { AdminRolesGuard } from '../../middlewares/admin-role-guard.middleware';
|
||||
import { Authenticated } from '../../decorators/authenticated.decorator';
|
||||
import { AllJobStatusResponseDto } from './response-dto/all-job-status-response.dto';
|
||||
import { GetJobDto } from './dto/get-job.dto';
|
||||
import { JobStatusResponseDto } from './response-dto/job-status-response.dto';
|
||||
|
||||
import { JobCommandDto } from './dto/job-command.dto';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@UseGuards(AdminRolesGuard)
|
||||
@Authenticated({ admin: true })
|
||||
@ApiTags('Job')
|
||||
@ApiBearerAuth()
|
||||
@Controller('jobs')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Controller, Get, UseGuards } from '@nestjs/common';
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { ServerInfoService } from './server-info.service';
|
||||
import { serverVersion } from '../../constants/server_version.constant';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
|
@ -6,8 +6,7 @@ import { ServerPingResponse } from './response-dto/server-ping-response.dto';
|
|||
import { ServerVersionReponseDto } from './response-dto/server-version-response.dto';
|
||||
import { ServerInfoResponseDto } from './response-dto/server-info-response.dto';
|
||||
import { ServerStatsResponseDto } from './response-dto/server-stats-response.dto';
|
||||
import { JwtAuthGuard } from '../../modules/immich-jwt/guards/jwt-auth.guard';
|
||||
import { AdminRolesGuard } from '../../middlewares/admin-role-guard.middleware';
|
||||
import { Authenticated } from '../../decorators/authenticated.decorator';
|
||||
|
||||
@ApiTags('Server Info')
|
||||
@Controller('server-info')
|
||||
|
@ -29,8 +28,7 @@ export class ServerInfoController {
|
|||
return serverVersion;
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@UseGuards(AdminRolesGuard)
|
||||
@Authenticated({ admin: true })
|
||||
@Get('/stats')
|
||||
async getStats(): Promise<ServerStatsResponseDto> {
|
||||
return await this.serverInfoService.getStats();
|
||||
|
|
|
@ -4,7 +4,6 @@ import {
|
|||
Post,
|
||||
Body,
|
||||
Param,
|
||||
UseGuards,
|
||||
ValidationPipe,
|
||||
Put,
|
||||
Query,
|
||||
|
@ -14,10 +13,9 @@ import {
|
|||
ParseBoolPipe,
|
||||
} from '@nestjs/common';
|
||||
import { UserService } from './user.service';
|
||||
import { JwtAuthGuard } from '../../modules/immich-jwt/guards/jwt-auth.guard';
|
||||
import { Authenticated } from '../../decorators/authenticated.decorator';
|
||||
import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator';
|
||||
import { CreateUserDto } from './dto/create-user.dto';
|
||||
import { AdminRolesGuard } from '../../middlewares/admin-role-guard.middleware';
|
||||
import { UpdateUserDto } from './dto/update-user.dto';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import { profileImageUploadOption } from '../../config/profile-image-upload.config';
|
||||
|
@ -33,7 +31,7 @@ import { CreateProfileImageResponseDto } from './response-dto/create-profile-ima
|
|||
export class UserController {
|
||||
constructor(private readonly userService: UserService) {}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Authenticated()
|
||||
@ApiBearerAuth()
|
||||
@Get()
|
||||
async getAllUsers(
|
||||
|
@ -48,16 +46,15 @@ export class UserController {
|
|||
return await this.userService.getUserById(userId);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Authenticated()
|
||||
@ApiBearerAuth()
|
||||
@Get('me')
|
||||
async getMyUserInfo(@GetAuthUser() authUser: AuthUserDto): Promise<UserResponseDto> {
|
||||
return await this.userService.getUserInfo(authUser);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Authenticated({ admin: true })
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AdminRolesGuard)
|
||||
@Post()
|
||||
async createUser(
|
||||
@Body(new ValidationPipe({ transform: true })) createUserDto: CreateUserDto,
|
||||
|
@ -70,7 +67,7 @@ export class UserController {
|
|||
return await this.userService.getUserCount();
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Authenticated()
|
||||
@ApiBearerAuth()
|
||||
@Put()
|
||||
async updateUser(
|
||||
|
@ -81,7 +78,7 @@ export class UserController {
|
|||
}
|
||||
|
||||
@UseInterceptors(FileInterceptor('file', profileImageUploadOption))
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Authenticated()
|
||||
@ApiBearerAuth()
|
||||
@ApiConsumes('multipart/form-data')
|
||||
@ApiBody({
|
||||
|
|
16
server/apps/immich/src/decorators/authenticated.decorator.ts
Normal file
16
server/apps/immich/src/decorators/authenticated.decorator.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { UseGuards } from '@nestjs/common';
|
||||
import { AdminRolesGuard } from '../middlewares/admin-role-guard.middleware';
|
||||
import { JwtAuthGuard } from '../modules/immich-jwt/guards/jwt-auth.guard';
|
||||
|
||||
interface AuthenticatedOptions {
|
||||
admin?: boolean;
|
||||
}
|
||||
|
||||
export const Authenticated = (options?: AuthenticatedOptions) => {
|
||||
const guards: Parameters<typeof UseGuards> = [JwtAuthGuard];
|
||||
options = options || {};
|
||||
if (options.admin) {
|
||||
guards.push(AdminRolesGuard);
|
||||
}
|
||||
return UseGuards(...guards);
|
||||
};
|
|
@ -1,42 +1,18 @@
|
|||
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { UserEntity } from '@app/database/entities/user.entity';
|
||||
import { ImmichJwtService } from '../modules/immich-jwt/immich-jwt.service';
|
||||
import { CanActivate, ExecutionContext, Injectable, Logger } from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
|
||||
@Injectable()
|
||||
export class AdminRolesGuard implements CanActivate {
|
||||
constructor(
|
||||
private reflector: Reflector,
|
||||
private jwtService: ImmichJwtService,
|
||||
@InjectRepository(UserEntity)
|
||||
private userRepository: Repository<UserEntity>,
|
||||
) {}
|
||||
logger = new Logger(AdminRolesGuard.name);
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
let accessToken = '';
|
||||
|
||||
if (request.headers['authorization']) {
|
||||
accessToken = request.headers['authorization'].split(' ')[1];
|
||||
} else if (request.cookies['immich_access_token']) {
|
||||
accessToken = request.cookies['immich_access_token'];
|
||||
} else {
|
||||
const request = context.switchToHttp().getRequest<Request>();
|
||||
const isAdmin = request.user?.isAdmin || false;
|
||||
if (!isAdmin) {
|
||||
this.logger.log(`Denied access to admin only route: ${request.path}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const { userId } = await this.jwtService.validateToken(accessToken);
|
||||
|
||||
if (!userId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const user = await this.userRepository.findOne({ where: { id: userId } });
|
||||
if (!user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.isAdmin;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue