Добавлена работа с пользователями по всем методам, добавлена авторизация пользователей

This commit is contained in:
vigdorov
2020-07-26 22:18:59 +03:00
parent baeded4a7a
commit 3711ef5f8f
10 changed files with 729 additions and 44 deletions

View File

@ -83,7 +83,9 @@ export class UsersController {
return await this.userService.removeOne(request.params.login);
}
@Options()
@Options([
'', ':login'
])
@Header(...ALLOW_ORIGIN_ALL)
@Header(...ALLOW_METHOD)
@Header(...ALLOW_CREDENTIALS)

View File

@ -2,11 +2,6 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import {ApiProperty} from '@nestjs/swagger';
import { Document } from 'mongoose';
interface Token {
token: string;
expired_at: string;
}
export class CreateUserRequest {
@ApiProperty()
login: string;
@ -49,12 +44,38 @@ export class UserModel {
@ApiProperty()
is_admin: boolean;
}
export class AuthRequest {
@ApiProperty()
login: string;
@ApiProperty()
access_token: Token[];
password: string;
}
export class CheckAuthTokenRequest {
@ApiProperty()
access_token: string;
@ApiProperty()
refresh_token: Token[];
host: string;
@ApiProperty()
agent: string;
}
export class RefreshAuthRequest {
@ApiProperty()
refresh_token: string;
}
export class TokenResponse {
@ApiProperty()
access_token: string;
@ApiProperty()
refresh_token: string;
}
@Schema()
@ -81,22 +102,6 @@ export class User extends Document {
type: Boolean,
})
is_admin: boolean;
@Prop({
type: [{
token: String,
expired_at: String,
}]
})
access_token: Token[];
@Prop({
type: [{
token: String,
expired_at: String,
}]
})
refresh_token: Token[];
}
@Schema()

View File

@ -1,8 +1,18 @@
import {Model, Connection, Document} from 'mongoose';
import {Injectable, NotFoundException, BadGatewayException} from '@nestjs/common';
import {Injectable, NotFoundException, BadGatewayException, UnauthorizedException} from '@nestjs/common';
import {InjectConnection} from '@nestjs/mongoose';
import {DB_NAME, USERS_CONTROLLER} from 'src/consts';
import {User, UserSchema, CreateUserRequest, UserResponse, UserModel, UpdateUserRequest} from './users.schema';
import {DB_NAME, USERS_CONTROLLER, SECRET_JWT_ACCESS_KEY, SECRET_JWT_REFRESH_KEY} from 'src/consts';
import {User, UserSchema, CreateUserRequest, UserResponse, UserModel, UpdateUserRequest, TokenResponse} from './users.schema';
import * as bcrypt from 'bcrypt';
import * as jwt from 'jsonwebtoken';
interface Token {
login: string;
host: string;
agent: string;
iat: number;
exp: number;
}
const validateModel = async (user: Document) => {
try {
@ -17,8 +27,6 @@ const prepareUserToUserModel = (user: User): UserModel => ({
avatar: user.avatar,
password: user.password,
is_admin: user.is_admin,
access_token: user.access_token,
refresh_token: user.refresh_token,
});
const prepareUserToUserResponse = (user: User): UserResponse => ({
@ -62,8 +70,15 @@ export class UserService {
throw new NotFoundException(`Пользователь с логином ${user.login} уже существует`);
}
const salt = await bcrypt.genSalt(10);
const password = await bcrypt.hash(user.password, salt);
const Model = await this.userModel();
const createUser = new Model(user);
const createUser = new Model({
...user,
salt,
password,
});
await validateModel(createUser);
const savedUser = await createUser.save();
@ -97,4 +112,67 @@ export class UserService {
return prepareUserToUserResponse(searchUser);
}
checkPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}
generateTokens(login: string, host: string, agent: string): TokenResponse {
const access_token = jwt.sign({
login,
host,
agent,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (60 * 2), // секунды * минуты
}, SECRET_JWT_ACCESS_KEY);
const refresh_token = jwt.sign({
login,
host,
agent,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (60 * 60 * 24 * 1), // секунды * минуты * часы * дни
}, SECRET_JWT_REFRESH_KEY);
return {
access_token,
refresh_token,
};
}
async authUser(login: string, password: string, host: string, agent: string): Promise<TokenResponse> {
const searchUser = await this.findUser(login);
if (searchUser && await this.checkPassword(password, searchUser.password)) {
return this.generateTokens(login, host, agent);
}
throw new UnauthorizedException('Не верный пользователь или пароль');
}
verifyToken(token: string, secret: string): void {
try {
jwt.verify(token, secret);
} catch (e) {
throw new UnauthorizedException('Авторизация устарела');
}
}
checkToken(token: Token, host: string, agent: string): boolean {
return token.host === host && token.agent === agent;
}
async refreshAuth(refresh_token: string, host: string, agent: string): Promise<TokenResponse> {
this.verifyToken(refresh_token, SECRET_JWT_REFRESH_KEY);
const token = jwt.decode(refresh_token) as Token;
const searchUser = await this.findUser(token.login);
if (searchUser && this.checkToken(token, host, agent)) {
return this.generateTokens(token.login, host, agent);
}
throw new UnauthorizedException('Не санкционированный запрос');
}
async checkAccessToken(access_token: string, host: string, agent: string): Promise<boolean> {
this.verifyToken(access_token, SECRET_JWT_ACCESS_KEY);
const token = jwt.decode(access_token) as Token;
const searchUser = await this.findUser(token.login);
return searchUser && this.checkToken(token, host, agent);
}
}