jwt

parent 7b6af307
...@@ -22,13 +22,18 @@ ...@@ -22,13 +22,18 @@
"dependencies": { "dependencies": {
"@nestjs/common": "^11.0.1", "@nestjs/common": "^11.0.1",
"@nestjs/core": "^11.0.1", "@nestjs/core": "^11.0.1",
"@nestjs/jwt": "^11.0.0",
"@nestjs/mapped-types": "*", "@nestjs/mapped-types": "*",
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.0.1", "@nestjs/platform-express": "^11.0.1",
"@nestjs/typeorm": "^11.0.0", "@nestjs/typeorm": "^11.0.0",
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.1", "class-validator": "^0.14.1",
"mysql2": "^3.14.0", "mysql2": "^3.14.0",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"pg": "^8.14.1", "pg": "^8.14.1",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
...@@ -46,6 +51,8 @@ ...@@ -46,6 +51,8 @@
"@types/express": "^5.0.0", "@types/express": "^5.0.0",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^22.10.7", "@types/node": "^22.10.7",
"@types/passport-jwt": "^4.0.1",
"@types/passport-local": "^1.0.38",
"@types/supertest": "^6.0.2", "@types/supertest": "^6.0.2",
"eslint": "^9.18.0", "eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1", "eslint-config-prettier": "^10.0.1",
......
This diff is collapsed.
...@@ -4,8 +4,9 @@ import { CategoryModule } from './category/category.module'; ...@@ -4,8 +4,9 @@ import { CategoryModule } from './category/category.module';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { Product } from './product/entities/product.entity'; import { Product } from './product/entities/product.entity';
import { Category } from './category/entities/category.entity'; import { Category } from './category/entities/category.entity';
import { UserModule } from './user/user.module';
import { User } from './user/entities/user.entity'; import { User } from './user/entities/user.entity';
import { UserModule } from './user/user.module';
import { AuthModule } from './auth/auth.module';
@Module({ @Module({
imports: [ imports: [
...@@ -26,6 +27,7 @@ import { User } from './user/entities/user.entity'; ...@@ -26,6 +27,7 @@ import { User } from './user/entities/user.entity';
ProductModule, ProductModule,
CategoryModule, CategoryModule,
UserModule, UserModule,
AuthModule,
], ],
controllers: [], controllers: [],
providers: [], providers: [],
......
import { Controller, Post, Body } from '@nestjs/common';
import { AuthService } from './auth.service';
import { RegisterDto } from './dto/register.dto';
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Post('register')
create(@Body() regiterAuthDto: RegisterDto) {
return this.authService.register(regiterAuthDto);
}
@Post('login')
login(@Body() body: { username: string; password: string }) {
return this.authService.login(body.username, body.password);
}
}
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UserModule } from 'src/user/user.module';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from 'src/common/strategy/jwt.strategy';
@Module({
imports: [
UserModule,
PassportModule,
JwtModule.register({
global: true,
secret: 'test',
}),
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy],
})
export class AuthModule {}
import {
Injectable,
NotFoundException,
UnauthorizedException,
} from '@nestjs/common';
import { RegisterDto } from './dto/register.dto';
import { UserService } from 'src/user/user.service';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcrypt';
const SALT_WORK_FACTOR = 10;
@Injectable()
export class AuthService {
constructor(
private userService: UserService,
private jwtService: JwtService,
) {}
async register(registerAuthDto: RegisterDto) {
const { accessToken, refreshToken } =
await this.generateToken(registerAuthDto);
const salt = await bcrypt.genSalt(SALT_WORK_FACTOR);
registerAuthDto.password = await bcrypt.hash(
registerAuthDto.password,
salt,
);
const user = await this.userService.create({
...registerAuthDto,
refreshToken,
});
return { accessToken, id: user.id, username: user.username };
}
async login(username: string, password: string) {
const user = await this.userService.findOneByUserName(username);
if (!user) throw new NotFoundException(' User not fount ');
const isMatch = await bcrypt.compare(password, user?.password || '');
if (!isMatch) throw new UnauthorizedException('Неверный логин или пароль');
const { accessToken } = await this.generateToken({ username, password });
return { accessToken, id: user.id, username: user.username };
}
async signToken(registerAuthDto: RegisterDto, expiresIn: string) {
return await this.jwtService.signAsync(
{
username: registerAuthDto.username,
password: registerAuthDto.password,
},
{
secret: 'test',
expiresIn,
},
);
}
async validateUser(
username: string,
pass: string,
): Promise<{ id: number; username: string } | null> {
const user = await this.userService.findOneByUserName(username);
if (user && user.password === pass) {
return {
id: user.id,
username: user.username,
};
}
return null;
}
async generateToken(registerAuthDto: RegisterDto) {
const accessToken = await this.signToken(registerAuthDto, '30m');
const refreshToken = await this.signToken(registerAuthDto, '7d');
return {
accessToken,
refreshToken,
};
}
}
import { IsNotEmpty, IsString } from 'class-validator';
export class RegisterDto {
@IsString()
@IsNotEmpty()
username: string;
@IsString()
@IsNotEmpty()
password: string;
}
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: 'test',
});
}
validate(payload: { username: string }) {
return { username: payload.username };
}
}
import { Controller, Get, Post, Body, Param, Delete } from '@nestjs/common'; import {
Controller,
Get,
Post,
Body,
Param,
Delete,
UseGuards,
} from '@nestjs/common';
import { ProductService } from './product.service'; import { ProductService } from './product.service';
import { CreateProductDto } from './dto/create-product.dto'; import { CreateProductDto } from './dto/create-product.dto';
import { JwtAuthGuard } from 'src/common/guards/jwt-auth.guarf';
@Controller('product') @Controller('product')
export class ProductController { export class ProductController {
...@@ -11,6 +20,7 @@ export class ProductController { ...@@ -11,6 +20,7 @@ export class ProductController {
return this.productService.create(createProductDto); return this.productService.create(createProductDto);
} }
@UseGuards(JwtAuthGuard)
@Get() @Get()
findAll() { findAll() {
return this.productService.findAll(); return this.productService.findAll();
......
import { IsNotEmpty, IsString, Length } from 'class-validator'; import { IsNotEmpty, IsString } from 'class-validator';
export class CreateUserDto { export class CreateUserDto {
@IsString() @IsString()
@IsNotEmpty() @IsNotEmpty()
@Length(4, 50)
username: string; username: string;
@IsString() @IsString()
@IsNotEmpty() @IsNotEmpty()
@Length(4, 50)
password: string; password: string;
@IsString()
refreshToken: string;
} }
...@@ -10,4 +10,7 @@ export class User { ...@@ -10,4 +10,7 @@ export class User {
@Column() @Column()
password: string; password: string;
@Column({ nullable: true })
refreshToken?: string;
} }
import { Controller, Get, Post, Body } from '@nestjs/common'; import { Controller, Get, Post, Body, Param, Delete } from '@nestjs/common';
import { UserService } from './user.service'; import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto'; import { CreateUserDto } from './dto/create-user.dto';
...@@ -6,18 +6,23 @@ import { CreateUserDto } from './dto/create-user.dto'; ...@@ -6,18 +6,23 @@ import { CreateUserDto } from './dto/create-user.dto';
export class UserController { export class UserController {
constructor(private readonly userService: UserService) {} constructor(private readonly userService: UserService) {}
@Post('register') @Post()
register(@Body() createUserDto: CreateUserDto) { create(@Body() createUserDto: CreateUserDto) {
return this.userService.register(createUserDto); return this.userService.create(createUserDto);
} }
@Post('login') @Get()
login(@Body() createUserDto: CreateUserDto) { findAll() {
return this.userService.login(createUserDto); return this.userService.findAll();
} }
@Get() @Get(':id')
logout() { findOne(@Param('id') id: string) {
return this.userService.logout(); return this.userService.findOne(+id);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.userService.remove(+id);
} }
} }
import { TypeOrmModule } from '@nestjs/typeorm';
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { UserService } from './user.service'; import { UserService } from './user.service';
import { UserController } from './user.controller'; import { UserController } from './user.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity'; import { User } from './entities/user.entity';
@Module({ @Module({
imports: [TypeOrmModule.forFeature([User])], imports: [TypeOrmModule.forFeature([User])],
controllers: [UserController], controllers: [UserController],
providers: [UserService], providers: [UserService],
exports: [UserService],
}) })
export class UserModule {} export class UserModule {}
...@@ -3,43 +3,41 @@ import { CreateUserDto } from './dto/create-user.dto'; ...@@ -3,43 +3,41 @@ import { CreateUserDto } from './dto/create-user.dto';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { User } from './entities/user.entity'; import { User } from './entities/user.entity';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import * as bcrypt from 'bcrypt';
const SALT_WORK_FACTOR = 10;
@Injectable() @Injectable()
export class UserService { export class UserService {
constructor(@InjectRepository(User) private userRepo: Repository<User>) {} constructor(@InjectRepository(User) private userRepo: Repository<User>) {}
async register(createUserDto: CreateUserDto) { async create(createUserDto: CreateUserDto): Promise<User> {
const salt = await bcrypt.genSalt(SALT_WORK_FACTOR); const isMatchUser = await this.userRepo.findOneBy({
createUserDto.password = await bcrypt.hash(createUserDto.password, salt); username: createUserDto.username,
});
if (isMatchUser) throw new Error('Юзер с таким логином уже есть');
const user = this.userRepo.create(createUserDto); const user = this.userRepo.create(createUserDto);
await this.userRepo.save(user); await this.userRepo.save(user);
return user; return user;
} }
async login(createUserDto: CreateUserDto) { async findAll(): Promise<User[]> {
const user = await this.userRepo.findOneBy({ return await this.userRepo.find();
username: createUserDto.username, }
});
if (!user) new NotFoundException('User not found');
// password = 2131
const isMatch = await bcrypt.compare(
createUserDto.password,
user?.password || '',
);
if (isMatch) { async findOne(id: number): Promise<User | null> {
return "SUCCESS LOGIN"; return await this.userRepo.findOneBy({ id });
} else {
return null;
} }
async findOneByUserName(username: string): Promise<User | null> {
return await this.userRepo.findOneBy({ username });
} }
logout() { async remove(id: number): Promise<number> {
return `This action returns a user`; const user = await this.userRepo.findOneBy({ id });
if (!user) throw new NotFoundException(' User not found ');
await this.userRepo.delete({ id });
return id;
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment