auth : update
This commit is contained in:
@@ -7,6 +7,6 @@ export class RequestOtpDto {
|
|||||||
@IsNotEmpty({ message: AuthMessage.PHONE_NOT_EMPTY })
|
@IsNotEmpty({ message: AuthMessage.PHONE_NOT_EMPTY })
|
||||||
@Length(11, 11, { message: AuthMessage.PHONE_SHOULD_BE_11_DIGIT })
|
@Length(11, 11, { message: AuthMessage.PHONE_SHOULD_BE_11_DIGIT })
|
||||||
@IsMobilePhone("fa-IR", {}, { message: AuthMessage.INVALID_PHONE_FORMAT })
|
@IsMobilePhone("fa-IR", {}, { message: AuthMessage.INVALID_PHONE_FORMAT })
|
||||||
@ApiProperty({ description: "phone number", default: "09922320740" })
|
@ApiProperty({ description: "phone number", default: "09185290775" })
|
||||||
phone: string;
|
phone: string;
|
||||||
}
|
}
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsMobilePhone, IsNotEmpty, IsNumberString, IsEnum, Length } from "class-validator";
|
||||||
|
|
||||||
|
import { AuthMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
|
export enum ResellerType {
|
||||||
|
agent = 'agent',
|
||||||
|
reseller = 'reseller'
|
||||||
|
}
|
||||||
|
|
||||||
|
export class VerifyResellerOtpDto {
|
||||||
|
@IsNotEmpty({ message: AuthMessage.PHONE_NOT_EMPTY })
|
||||||
|
@Length(11, 11, { message: AuthMessage.PHONE_SHOULD_BE_11_DIGIT })
|
||||||
|
@IsMobilePhone("fa-IR", {}, { message: AuthMessage.INVALID_PHONE_FORMAT })
|
||||||
|
@ApiProperty({ description: "phone number", default: "09185290775" })
|
||||||
|
phone: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: "OTP code received via SMS", example: "" })
|
||||||
|
@IsNotEmpty({ message: AuthMessage.OTP_NOT_EMPTY })
|
||||||
|
@IsNumberString(undefined, { message: AuthMessage.OTP_FORMAT_INVALID })
|
||||||
|
@Length(5, 5, { message: AuthMessage.OTP_FORMAT_INVALID })
|
||||||
|
code: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ResellerType })
|
||||||
|
@IsEnum(ResellerType)
|
||||||
|
type: ResellerType;
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import { UserDec } from "../../common/decorators/user.decorator";
|
|||||||
import { User } from "../users/entities/user.entity";
|
import { User } from "../users/entities/user.entity";
|
||||||
import { ForgetPasswordDto } from "./DTO/forget-password.dto";
|
import { ForgetPasswordDto } from "./DTO/forget-password.dto";
|
||||||
import { VerifyForgotPasswordOtpDto } from "./DTO/verify-forgot-otp.dto";
|
import { VerifyForgotPasswordOtpDto } from "./DTO/verify-forgot-otp.dto";
|
||||||
|
import { VerifyResellerOtpDto } from "./DTO/verify-reseller-otp.dto";
|
||||||
|
|
||||||
@ApiTags("Auth")
|
@ApiTags("Auth")
|
||||||
@Controller("auth")
|
@Controller("auth")
|
||||||
@@ -80,7 +81,7 @@ export class AuthController {
|
|||||||
@ApiOperation({ summary: "verify otp for login" })
|
@ApiOperation({ summary: "verify otp for login" })
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("otp/verify/reseller")
|
@Post("otp/verify/reseller")
|
||||||
resellerVerifyOtp(@Body() verifyOtpDto: VerifyOtpDto) {
|
resellerVerifyOtp(@Body() verifyOtpDto: VerifyResellerOtpDto) {
|
||||||
return this.authService.resellerVerifyLoginOtp(verifyOtpDto);
|
return this.authService.resellerVerifyLoginOtp(verifyOtpDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,15 +16,13 @@ export class ResellerRouteGuard implements CanActivate {
|
|||||||
|
|
||||||
if (!requiredReseller) return true;
|
if (!requiredReseller) return true;
|
||||||
|
|
||||||
console.log('hi')
|
|
||||||
const req = context.switchToHttp().getRequest<FastifyRequest>();
|
const req = context.switchToHttp().getRequest<FastifyRequest>();
|
||||||
const user = req.user;
|
const user = req.user;
|
||||||
|
|
||||||
console.log(user)
|
|
||||||
|
|
||||||
if (!user) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
if (!user) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
||||||
|
|
||||||
// if (!user.isReseller) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
if (!user.resellerType) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { PermissionEnum } from "../../users/enums/permission.enum";
|
import { PermissionEnum } from "../../users/enums/permission.enum";
|
||||||
|
import { ResellerType } from "../DTO/verify-reseller-otp.dto";
|
||||||
// import { RoleEnum } from "../../users/enums/role.enum";
|
// import { RoleEnum } from "../../users/enums/role.enum";
|
||||||
|
|
||||||
export interface ITokenPayload {
|
export interface ITokenPayload {
|
||||||
id: string;
|
id: string;
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
isReseller: boolean;
|
resellerType?: ResellerType;
|
||||||
permissions: PermissionEnum[];
|
permissions: PermissionEnum[];
|
||||||
audience?: string; // Client application identifier for SSO
|
audience?: string; // Client application identifier for SSO
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { ForgetPasswordDto } from "../DTO/forget-password.dto";
|
|||||||
import { VerifyForgotPasswordOtpDto } from "../DTO/verify-forgot-otp.dto";
|
import { VerifyForgotPasswordOtpDto } from "../DTO/verify-forgot-otp.dto";
|
||||||
import { EmailService } from "../../utils/providers/email.service";
|
import { EmailService } from "../../utils/providers/email.service";
|
||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
|
import { ResellerType, VerifyResellerOtpDto } from "../DTO/verify-reseller-otp.dto";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
@@ -115,8 +116,14 @@ export class AuthService {
|
|||||||
async requestLoginOtpReseller(requestOtpDto: RequestOtpDto) {
|
async requestLoginOtpReseller(requestOtpDto: RequestOtpDto) {
|
||||||
const { phone } = requestOtpDto;
|
const { phone } = requestOtpDto;
|
||||||
|
|
||||||
// check if agent with this phone exist or not
|
|
||||||
await this.checkAgentExistWithPhone(phone)
|
let user: User | null = null
|
||||||
|
|
||||||
|
user = (await this.usersService.getAgentByUserPhone(phone)) ?? (await this.usersService.getResellerByUserPhone(phone))
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new BadRequestException(AuthMessage.USER_NOT_FOUND)
|
||||||
|
}
|
||||||
|
|
||||||
const existCode = await this.otpService.checkExistOtp(phone, "LOGIN_RESELLER_AGENT");
|
const existCode = await this.otpService.checkExistOtp(phone, "LOGIN_RESELLER_AGENT");
|
||||||
if (existCode) {
|
if (existCode) {
|
||||||
@@ -227,15 +234,18 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
//****************** */
|
//****************** */
|
||||||
|
|
||||||
async resellerVerifyLoginOtp(verifyOtpDto: VerifyOtpDto) {
|
async resellerVerifyLoginOtp(verifyOtpDto: VerifyResellerOtpDto) {
|
||||||
const { code, phone } = verifyOtpDto;
|
const { code, phone, type } = verifyOtpDto;
|
||||||
|
|
||||||
await this.checkResellerOtpWithPhone(phone, code)
|
await this.checkResellerOtpWithPhone(phone, code)
|
||||||
|
|
||||||
const { agent, reseller } = await this.checkAgentExistWithPhone(phone);
|
let user: User | null = null
|
||||||
|
|
||||||
|
if (type == ResellerType.agent) {
|
||||||
const user: User | null = agent ?? reseller
|
user = await this.usersService.getAgentByUserPhone(phone)
|
||||||
|
} else if (type == ResellerType.reseller) {
|
||||||
|
user = await this.usersService.getResellerByUserPhone(phone)
|
||||||
|
}
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new BadRequestException(AuthMessage.USER_NOT_FOUND)
|
throw new BadRequestException(AuthMessage.USER_NOT_FOUND)
|
||||||
@@ -243,7 +253,7 @@ export class AuthService {
|
|||||||
|
|
||||||
if (user.deletedAt) throw new BadRequestException(AuthMessage.ACCESS_DENIED);
|
if (user.deletedAt) throw new BadRequestException(AuthMessage.ACCESS_DENIED);
|
||||||
|
|
||||||
const tokens = await this.tokensService.generateTokensForReseller(user);
|
const tokens = await this.tokensService.generateTokensForReseller(user, type);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: AuthMessage.LOGIN_SUCCESS,
|
message: AuthMessage.LOGIN_SUCCESS,
|
||||||
@@ -310,20 +320,7 @@ export class AuthService {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//****************** */
|
|
||||||
//****************** */
|
|
||||||
private async checkAgentExistWithPhone(phone: string) {
|
|
||||||
|
|
||||||
const { reseller } = await this.usersService.getResellerByUserPhone(phone);
|
|
||||||
|
|
||||||
const { agent } = await this.usersService.getAgentByUserPhone(phone);
|
|
||||||
|
|
||||||
if (!reseller && !agent) {
|
|
||||||
throw new BadRequestException(AuthMessage.USER_NOT_FOUND)
|
|
||||||
}
|
|
||||||
|
|
||||||
return { reseller, agent }
|
|
||||||
}
|
|
||||||
//****************** */
|
//****************** */
|
||||||
//****************** */
|
//****************** */
|
||||||
async requestForgotPasswordOtp(dto: ForgetPasswordDto) {
|
async requestForgotPasswordOtp(dto: ForgetPasswordDto) {
|
||||||
@@ -383,7 +380,5 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
//****************** */
|
//****************** */
|
||||||
//****************** */
|
//****************** */
|
||||||
// private checkUserIsAgent(roles: Role[]) {
|
|
||||||
// return roles.some((role) => role.isAgent);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ export class SSOService {
|
|||||||
// Generate token with client-specific audience
|
// Generate token with client-specific audience
|
||||||
const payload: ITokenPayload = {
|
const payload: ITokenPayload = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isReseller:false,
|
|
||||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
||||||
audience: clientId,
|
audience: clientId,
|
||||||
@@ -106,7 +105,6 @@ export class SSOService {
|
|||||||
const payload: ITokenPayload = {
|
const payload: ITokenPayload = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||||
isReseller:false,
|
|
||||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
||||||
audience: clientId,
|
audience: clientId,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { AuthMessage } from "../../../common/enums/message.enum";
|
|||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
import { RefreshTokensRepository } from "../../users/repositories/refresh-token.repository";
|
import { RefreshTokensRepository } from "../../users/repositories/refresh-token.repository";
|
||||||
import { ITokenPayload } from "../interfaces/IToken-payload";
|
import { ITokenPayload } from "../interfaces/IToken-payload";
|
||||||
|
import { ResellerType } from "../DTO/verify-reseller-otp.dto";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TokensService {
|
export class TokensService {
|
||||||
@@ -27,19 +28,18 @@ export class TokensService {
|
|||||||
{
|
{
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||||
isReseller: false,
|
|
||||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
||||||
},
|
},
|
||||||
queryRunner,
|
queryRunner,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
async generateTokensForReseller(user: User, queryRunner?: QueryRunner) {
|
async generateTokensForReseller(user: User, resellerType: ResellerType, queryRunner?: QueryRunner) {
|
||||||
return this.generateAccessAndRefreshToken(
|
return this.generateAccessAndRefreshToken(
|
||||||
{
|
{
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
isReseller: true,
|
resellerType,
|
||||||
permissions: [],
|
permissions: [],
|
||||||
},
|
},
|
||||||
queryRunner,
|
queryRunner,
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ export class JwtStrategy extends PassportStrategy(Strategy, JWT_STRATEGY_NAME) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async validate(payload: ITokenPayload) {
|
async validate(payload: ITokenPayload) {
|
||||||
return { id: payload.id, permissions: payload.permissions, isAdmin: payload.isAdmin };
|
return {
|
||||||
|
id: payload.id,
|
||||||
|
permissions: payload.permissions,
|
||||||
|
isAdmin: payload.isAdmin,
|
||||||
|
resellerType: payload.resellerType
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user