Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
wermarter committed Dec 20, 2023
1 parent 6c0d9e2 commit 66250df
Show file tree
Hide file tree
Showing 25 changed files with 139 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { User } from 'src/domain/entity'
export const AuthContextToken = Symbol('AuthContext')

export interface IAuthContext {
ensureContextData(context: ExecutionContext): Promise<void>
populateContextData(context: ExecutionContext): Promise<void>
getData(): ContextData
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './context'
export * from './payload'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type AuthPayload = {
userId: string
}
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './puppeteer-service'
export * from './storage-service'
export * from './jwt-service'
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const JwtServiceToken = Symbol('JwtService')

export interface IJwtService {
sign(payload: any): string
verify(token: string): any
}
44 changes: 44 additions & 0 deletions apps/levansy-access-service/src/domain/use-case/auth/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { BadRequestException, Inject, Injectable } from '@nestjs/common'
import { LoginExceptionMsg } from '@diut/levansy-common'
import * as argon2 from 'argon2'

import { IUseCase } from '../interface'
import { UserFindOneUseCase } from '../user/find-one'
import { User } from 'src/domain/entity'
import { JwtService } from '@nestjs/jwt'
import { AuthPayload } from 'src/domain/interface'

export type AuthLoginUseCaseInput = { username: string; password: string }
export type AuthLoginUseCaseOutput = User & { jwtAccessToken: string }

@Injectable()
export class AuthLoginUseCase
implements IUseCase<AuthLoginUseCaseInput, AuthLoginUseCaseOutput>
{
constructor(
private userFindOneUseCase: UserFindOneUseCase,
private jwtService: JwtService,
) {}

async execute(input: AuthLoginUseCaseInput) {
const { username, password } = input

const user = await this.userFindOneUseCase.execute({ username })
if (!user) {
// TODO: abtract domain exception and logging
throw new BadRequestException(LoginExceptionMsg.USERNAME_NOT_EXIST)
}

const isCorrect = await argon2.verify(user.password, password)
if (!isCorrect) {
throw new BadRequestException(LoginExceptionMsg.WRONG_PASSWORD)
}

const authPayload: AuthPayload = {
userId: user._id,
}
const jwtAccessToken = await this.jwtService.signAsync(authPayload)

return { ...user, jwtAccessToken }
}
}
1 change: 1 addition & 0 deletions apps/levansy-access-service/src/domain/use-case/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './interface'
export * from './module'

export * from './auth/me'
export * from './auth/login'

export * from './user/find-one'

Expand Down
4 changes: 4 additions & 0 deletions apps/levansy-access-service/src/domain/use-case/module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ModuleMetadata } from '@nestjs/common'
import { JwtModule } from '@nestjs/jwt'
import { ConfigModule } from '@diut/nest-core'

import { BioProductCreateUseCase } from './bio-product/create'
import { BioProductUpdateUseCase } from './bio-product/update'
Expand All @@ -12,10 +14,12 @@ import { TestCategoryDeleteUseCase } from './test-category/delete'
import { TestCategorySearchUseCase } from './test-category/search'
import { AuthMeUseCase } from './auth/me'
import { UserFindOneUseCase } from './user/find-one'
import { AuthLoginUseCase } from './auth/login'

export const useCaseMetadata: ModuleMetadata = {
providers: [
AuthMeUseCase,
AuthLoginUseCase,

UserFindOneUseCase,

Expand Down
6 changes: 6 additions & 0 deletions apps/levansy-access-service/src/infrastructure/auth/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { SetMetadata } from '@nestjs/common'

export const JWT_STRATEGY_KEY = 'auth.jwt'

export const SKIP_JWT_KEY = 'SKIP_JWT_KEY'
export const SkipJWTGuard = SetMetadata(SKIP_JWT_KEY, true)
25 changes: 21 additions & 4 deletions apps/levansy-access-service/src/infrastructure/auth/context.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
import { ExecutionContext, Injectable, Scope } from '@nestjs/common'
import {
ExecutionContext,
Injectable,
Scope,
UnauthorizedException,
} from '@nestjs/common'
import { Request as ExpressRequest } from 'express'

import { ContextData, IAuthContext, User } from 'src/domain'
import {
AuthPayload,
ContextData,
IAuthContext,
UserFindOneUseCase,
} from 'src/domain'

@Injectable({ scope: Scope.REQUEST })
export class AuthContext implements IAuthContext {
private contextData: ContextData

async ensureContextData(executionContext: ExecutionContext) {
constructor(private userFindOneUseCase: UserFindOneUseCase) {}

async populateContextData(executionContext: ExecutionContext) {
const request = executionContext.switchToHttp().getRequest<ExpressRequest>()
const user = request.user as User
const payload = request.user as AuthPayload

const user = await this.userFindOneUseCase.execute({ _id: payload.userId })
if (!user) {
throw new UnauthorizedException('JWT_USERID_NOT_FOUND')
}

this.contextData = { user }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './jwt.guard'
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { JWT_STRATEGY_KEY, SKIP_JWT_KEY } from '../common'
import { Reflector } from '@nestjs/core'

@Injectable()
export class JwtAuthGuard
export class JwtGuard
extends AuthGuard(JWT_STRATEGY_KEY)
implements CanActivate
{
Expand Down
4 changes: 4 additions & 0 deletions apps/levansy-access-service/src/infrastructure/auth/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export * from './module'

export * from './guards'
export * from './strategies'
export * from './common'
18 changes: 16 additions & 2 deletions apps/levansy-access-service/src/infrastructure/auth/interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,29 @@ import {
NestInterceptor,
Scope,
} from '@nestjs/common'
import { Reflector } from '@nestjs/core'

import { AuthContextToken, IAuthContext } from 'src/domain'
import { SKIP_JWT_KEY } from './common'

@Injectable({ scope: Scope.REQUEST })
export class AuthInterceptor implements NestInterceptor<unknown> {
constructor(@Inject(AuthContextToken) private authContext: IAuthContext) {}
constructor(
@Inject(AuthContextToken) private authContext: IAuthContext,
private reflector: Reflector,
) {}

async intercept(context: ExecutionContext, next: CallHandler<unknown>) {
await this.authContext.ensureContextData(context)
const shouldSkip = this.reflector.getAllAndOverride<boolean>(SKIP_JWT_KEY, [
context.getHandler(),
context.getClass(),
])

if (shouldSkip === true) {
return next.handle()
}

await this.authContext.populateContextData(context)

return next.handle()
}
Expand Down
20 changes: 17 additions & 3 deletions apps/levansy-access-service/src/infrastructure/auth/module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { APP_INTERCEPTOR } from '@nestjs/core'
import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'
import { ModuleMetadata } from '@nestjs/common'
import { JwtModule } from '@nestjs/jwt'
import { JwtModule, JwtService } from '@nestjs/jwt'
import { ConfigModule } from '@diut/nest-core'

import { AuthContextToken } from 'src/domain'
import { AuthContextToken, IJwtService, JwtServiceToken } from 'src/domain'
import { AuthContext } from './context'
import { AuthInterceptor } from './interceptor'
import { JwtStrategy } from './strategies'
import { JwtGuard } from './guards'
import { AuthConfig, loadAuthConfig } from '../config'

export const authMetadata: ModuleMetadata = {
Expand All @@ -24,6 +26,11 @@ export const authMetadata: ModuleMetadata = {
}),
],
providers: [
JwtStrategy,
{
provide: APP_GUARD,
useClass: JwtGuard,
},
{
provide: AuthContextToken,
useClass: AuthContext,
Expand All @@ -32,5 +39,12 @@ export const authMetadata: ModuleMetadata = {
provide: APP_INTERCEPTOR,
useClass: AuthInterceptor,
},
{
provide: JwtServiceToken,
inject: [JwtService],
useFactory: (jwtService: JwtService): IJwtService => {
return jwtService
},
},
],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './jwt.strategy'
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {
} from 'passport-jwt'
import { NodeEnv } from '@diut/common'

import { AuthTokenPayload, JWT_STRATEGY_KEY } from '../common'
import { AppConfigToken, AuthConfigToken } from 'src/domain'
import { JWT_STRATEGY_KEY } from '../common'
import { AppConfigToken, AuthConfigToken, AuthPayload } from 'src/domain'
import { AppConfig, AuthConfig } from 'src/infrastructure/config'

@Injectable()
Expand All @@ -25,7 +25,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, JWT_STRATEGY_KEY) {
} satisfies StrategyOptions)
}

validate(payload: AuthTokenPayload, done: VerifiedCallback) {
validate(payload: AuthPayload, done: VerifiedCallback) {
done(null, payload)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,40 +1,25 @@
import { CustomHttpController, CustomHttpRoute } from '@diut/nest-core'
import { Body, UseGuards } from '@nestjs/common'
import { JwtService } from '@nestjs/jwt'
import { Body } from '@nestjs/common'

import { User, AuthMeUseCase } from 'src/domain'
import { AuthMeUseCase, AuthLoginUseCase } from 'src/domain'
import { AuthLoginRequestDto } from './dto/login.request-dto'
import { authRoutes } from './routes'
import { AuthTokenPayload, ReqUser, SkipJWTGuard } from './common'
import { JwtAuthGuard, LocalAuthGuard } from './guards'
import { SkipJWTGuard } from 'src/infrastructure/auth'

@CustomHttpController(authRoutes.controller)
export class AuthController {
constructor(
private authMeUseCase: AuthMeUseCase,
private jwtService: JwtService,
private authLoginUseCase: AuthLoginUseCase,
) {}

@CustomHttpRoute(authRoutes.login)
@UseGuards(LocalAuthGuard)
@SkipJWTGuard
async login(@ReqUser() user: User, @Body() body: AuthLoginRequestDto) {
const payload: AuthTokenPayload = {
sub: user._id,
}
const generatedAccessToken = await this.jwtService.signAsync(payload)

return {
...user,
_id: user._id,
generatedAccessToken,
}
login(@Body() body: AuthLoginRequestDto) {
return this.authLoginUseCase.execute(body)
}

@CustomHttpRoute({
path: 'me',
})
@UseGuards(JwtAuthGuard)
@CustomHttpRoute(authRoutes.me)
me() {
return this.authMeUseCase.execute()
}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const authRoutes = {
path: 'login',
method: RequestMethod.POST,
code: HttpStatus.OK,
serialize: LoginResponseDto,
// serialize: LoginResponseDto,
openApi: {
responses: [
{
Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit 66250df

Please sign in to comment.