auth
This commit is contained in:
6
api/src/model/dto/auth-code.dto.ts
Normal file
6
api/src/model/dto/auth-code.dto.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { IsNotEmpty } from 'class-validator';
|
||||
|
||||
export class AuthCodeDto {
|
||||
@IsNotEmpty()
|
||||
code: string;
|
||||
}
|
||||
9
api/src/model/dto/create-user.dto.ts
Normal file
9
api/src/model/dto/create-user.dto.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { IsEmail, IsNotEmpty } from 'class-validator';
|
||||
|
||||
export class CreateUserDto {
|
||||
@IsEmail()
|
||||
username: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
externalId: string;
|
||||
}
|
||||
2
api/src/model/dto/index.ts
Normal file
2
api/src/model/dto/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './login.dto';
|
||||
export * from './auth-code.dto';
|
||||
9
api/src/model/dto/login.dto.ts
Normal file
9
api/src/model/dto/login.dto.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { IsEmail, IsNotEmpty } from 'class-validator';
|
||||
|
||||
export class LoginDTO {
|
||||
@IsEmail()
|
||||
username: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
password: string;
|
||||
}
|
||||
2
api/src/model/entitites/index.ts
Normal file
2
api/src/model/entitites/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './sso.user.entity';
|
||||
export * from './user.entity';
|
||||
18
api/src/model/entitites/sso.user.entity.ts
Normal file
18
api/src/model/entitites/sso.user.entity.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Column, Entity, JoinColumn, OneToOne, PrimaryColumn } from 'typeorm';
|
||||
import { User } from './user.entity';
|
||||
|
||||
@Entity()
|
||||
export class SSOUser {
|
||||
@PrimaryColumn({ type: 'uuid', unique: true })
|
||||
externalId: string;
|
||||
|
||||
@OneToOne(() => User, (user) => user.external)
|
||||
@JoinColumn()
|
||||
user: User;
|
||||
|
||||
@Column({ nullable: true, type: 'text' })
|
||||
accessToken: string;
|
||||
|
||||
@Column({ nullable: true, type: 'text' })
|
||||
refreshToken: string;
|
||||
}
|
||||
44
api/src/model/entitites/user.entity.ts
Normal file
44
api/src/model/entitites/user.entity.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Exclude } from 'class-transformer';
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
OneToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { IUser } from '../interface';
|
||||
import { SSOUser } from './sso.user.entity';
|
||||
import { IsEmail } from 'class-validator';
|
||||
|
||||
@Entity()
|
||||
export class User implements IUser {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@IsEmail()
|
||||
@Column({ unique: true })
|
||||
username: string;
|
||||
|
||||
@Column({ name: 'first_name', default: '' })
|
||||
firstName: string;
|
||||
|
||||
@Column({ name: 'last_name', default: '' })
|
||||
lastName: string;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
createdAt: Date;
|
||||
|
||||
@Column({ default: null })
|
||||
lastLogin: Date;
|
||||
|
||||
@Exclude()
|
||||
@OneToOne(() => SSOUser, (sso) => sso.user, { eager: true, cascade: true })
|
||||
external: SSOUser;
|
||||
|
||||
@Exclude()
|
||||
@Column({ default: true })
|
||||
isActive: boolean;
|
||||
|
||||
accessToken?: string;
|
||||
refreshToken?: string;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export interface IExternalAccessPayload {
|
||||
username: string;
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
iss: string;
|
||||
aud: string;
|
||||
iat: number;
|
||||
exp: number;
|
||||
}
|
||||
3
api/src/model/interface/index.ts
Normal file
3
api/src/model/interface/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './user.interface';
|
||||
export * from './external-access-token.payload.interface';
|
||||
export * from './payload.interface';
|
||||
5
api/src/model/interface/payload.interface.ts
Normal file
5
api/src/model/interface/payload.interface.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface IPayload {
|
||||
id: string;
|
||||
username: string;
|
||||
type: 'access' | 'refresh';
|
||||
}
|
||||
10
api/src/model/interface/user.interface.ts
Normal file
10
api/src/model/interface/user.interface.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface IUser {
|
||||
id: string;
|
||||
username: string;
|
||||
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
|
||||
accessToken?: string;
|
||||
refreshToken?: string;
|
||||
}
|
||||
2
api/src/model/repositories/index.ts
Normal file
2
api/src/model/repositories/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './user.repository';
|
||||
export * from './ssouser.repository';
|
||||
18
api/src/model/repositories/ssouser.repository.ts
Normal file
18
api/src/model/repositories/ssouser.repository.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Repository, DataSource } from 'typeorm';
|
||||
import { SSOUser } from '../entitites';
|
||||
|
||||
@Injectable()
|
||||
export class SsoUserRepository extends Repository<SSOUser> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(SSOUser, dataSource.createEntityManager());
|
||||
}
|
||||
|
||||
findOneByUserId(id: string): Promise<SSOUser> {
|
||||
return this.findOne({ where: { user: { id: id } } });
|
||||
}
|
||||
|
||||
findByExternalId(id: string): Promise<SSOUser> {
|
||||
return this.findOne({ where: { externalId: id } });
|
||||
}
|
||||
}
|
||||
61
api/src/model/repositories/user.repository.ts
Normal file
61
api/src/model/repositories/user.repository.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { Repository, DataSource } from 'typeorm';
|
||||
import { User } from '../entitites';
|
||||
import { CreateUserDto } from '../dto/create-user.dto';
|
||||
import { SsoUserRepository } from './ssouser.repository';
|
||||
|
||||
@Injectable()
|
||||
export class UserRepository extends Repository<User> {
|
||||
constructor(
|
||||
dataSource: DataSource,
|
||||
private ssoRepo: SsoUserRepository,
|
||||
) {
|
||||
super(User, dataSource.createEntityManager());
|
||||
}
|
||||
|
||||
findByUsername(username: string): Promise<User> {
|
||||
return this.findOne({ where: { username }, relations: ['external'] });
|
||||
}
|
||||
|
||||
findById(id: string): Promise<User> {
|
||||
return this.findOne({ where: { id }, relations: ['external'] });
|
||||
}
|
||||
|
||||
async createUser(createUserDto: CreateUserDto): Promise<User> {
|
||||
if (
|
||||
!(await this.checkIfCanInserted(
|
||||
createUserDto.username,
|
||||
createUserDto.externalId,
|
||||
))
|
||||
) {
|
||||
throw new HttpException('user_exists', HttpStatus.UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
try {
|
||||
const created = this.create(createUserDto);
|
||||
const sso = this.ssoRepo.create({
|
||||
user: created,
|
||||
externalId: createUserDto.externalId,
|
||||
});
|
||||
created.external = sso;
|
||||
const user = await this.save(created);
|
||||
sso.user = user;
|
||||
this.ssoRepo.save(sso);
|
||||
return user;
|
||||
} catch {
|
||||
throw new HttpException(
|
||||
'not_successfull',
|
||||
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async checkIfCanInserted(
|
||||
username: string,
|
||||
externalId: string,
|
||||
): Promise<boolean> {
|
||||
const user = await this.findOneBy({ username });
|
||||
const sso = await this.ssoRepo.findByExternalId(externalId);
|
||||
return user == null && sso == null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user