This commit is contained in:
2025-06-22 21:17:39 +08:00
parent a96869f0ee
commit 0889225257
16 changed files with 72 additions and 50 deletions

View File

@@ -30,10 +30,12 @@ import { ThrottlerModule } from '@nestjs/throttler';
}),
PassportModule.register({ defaultStrategy: 'jwt' }),
ThrottlerModule.forRoot({
throttlers: [{
throttlers: [
{
limit: 1000,
ttl: 60000, // 1 minute
}],
},
],
}),
UserModule,
AuthModule,

View File

@@ -10,7 +10,6 @@ import { JwtStrategy } from './strategies/jwt.strategy';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { VerificationModule } from 'src/verification/verification.module';
import { OptionalAuthGuard } from './strategies/OptionalAuthGuard';
import { NotificationModule } from 'src/notification/notification.module';
@Module({
imports: [

View File

@@ -1,4 +1,8 @@
import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common';
import {
BadRequestException,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
@@ -37,7 +41,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
return {
...user,
sessionId
sessionId,
};
}
}

View File

@@ -3,7 +3,6 @@ import {
Body,
Controller,
Get,
Ip,
Param,
ParseUUIDPipe,
Post,

View File

@@ -1,30 +1,34 @@
import { BadRequestException, CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common';
import {
BadRequestException,
CanActivate,
ExecutionContext,
ForbiddenException,
Injectable,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Role } from 'src/auth/role.enum';
import { User } from 'src/user/entities/user.entity';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(
private reflector: Reflector,
) { }
constructor(private reflector: Reflector) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const requiredRoles = this.reflector.getAllAndOverride<Role[] | undefined>('roles', [
context.getHandler(),
context.getClass(),
]);
const requiredRoles = this.reflector.getAllAndOverride<Role[] | undefined>(
'roles',
[context.getHandler(), context.getClass()],
);
if (!requiredRoles) return true;
const request = context.switchToHttp().getRequest();
const user = request.user as (User | void);
const user = request.user as User | void;
if (!user) {
throw new BadRequestException('服务器内部错误');
}
if (!requiredRoles.some(role => user.roles.includes(role))) {
if (!requiredRoles.some((role) => user.roles.includes(role))) {
throw new ForbiddenException('权限不足');
}

View File

@@ -1,14 +1,13 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import Dm20151123, * as $Dm20151123 from '@alicloud/dm20151123';
import OpenApi, * as $OpenApi from '@alicloud/openapi-client';
import Client, * as $dm from "@alicloud/dm20151123";
import Util, * as $Util from '@alicloud/tea-util';
import * as $OpenApi from '@alicloud/openapi-client';
// import Client, * as $dm from '@alicloud/dm20151123';
import * as $Util from '@alicloud/tea-util';
import Credential, { Config } from '@alicloud/credentials';
@Injectable()
export class NotificationService {
private dm: Dm20151123;
constructor() {
@@ -23,7 +22,7 @@ export class NotificationService {
this.dm = new Dm20151123(config);
}
private getMailHtmlBody(option: { type: 'login-verify', code: string }) {
private getMailHtmlBody(option: { type: 'login-verify'; code: string }) {
if (option.type === 'login-verify') {
return `<!DOCTYPE html>
<html>
@@ -76,25 +75,31 @@ export class NotificationService {
</div>
</div>
</body>
</html>`
</html>`;
} else {
throw new Error('未配置的模版');
}
}
async sendMail(option: { type: 'login-verify', targetMail: string, code: string; }) {
async sendMail(option: {
type: 'login-verify';
targetMail: string;
code: string;
}) {
const runtime = new $Util.RuntimeOptions({});
const singleSendMailRequest = new $Dm20151123.SingleSendMailRequest({
accountName: "security@tonesc.cn",
accountName: 'security@tonesc.cn',
addressType: 1,
replyToAddress: false,
toAddress: `${option.targetMail}`,
subject: "【特恩的日志】登陆验证码",
htmlBody: this.getMailHtmlBody({ type: 'login-verify', code: option.code }),
textBody: "",
})
subject: '【特恩的日志】登陆验证码',
htmlBody: this.getMailHtmlBody({
type: 'login-verify',
code: option.code,
}),
textBody: '',
});
try {
await this.dm.singleSendMailWithOptions(singleSendMailRequest, runtime);

View File

@@ -40,7 +40,7 @@ export class UserService {
return this.userRepository.findOne({
where: {
userId,
}
},
});
}

View File

@@ -1,4 +1,10 @@
import { BadRequestException, Body, Controller, Post, UseGuards } from '@nestjs/common';
import {
BadRequestException,
Body,
Controller,
Post,
UseGuards,
} from '@nestjs/common';
import { SendVerificationCodeDto } from './dto/send-verification-code.dto';
import { VerificationService } from './verification.service';
import { Throttle, ThrottlerGuard } from '@nestjs/throttler';

View File

@@ -51,10 +51,12 @@ export class VerificationService {
this.saveCode(key, code);
this.logger.log(`Email[${email}] code: ${code}`);
// 发送验证码
await this.notificationService.sendMail({ type: 'login-verify', targetMail: email, code, }).catch(() => {
await this.notificationService
.sendMail({ type: 'login-verify', targetMail: email, code })
.catch(() => {
this.clearCode(key);
throw new BadRequestException('发送失败,请稍后再试');
})
});
return true;
}

View File

@@ -53,7 +53,7 @@ export default function Page() {
refreshSTSToken: async () => {
await storeMeta.refresh();
if (!storeMeta.stsTokenData) throw new Error();
const { AccessKeyId, AccessKeySecret, SecurityToken } = data;
const { AccessKeyId, AccessKeySecret, SecurityToken } = storeMeta.stsTokenData;
return {
accessKeyId: AccessKeyId,
accessKeySecret: AccessKeySecret,
@@ -65,6 +65,7 @@ export default function Page() {
ossStore.setStore(store);
ossStore.setWorkDir(`tone-page/${data.userId}`)
ossStore.loadObjectList();
// eslint-disable-next-line react-hooks/exhaustive-deps -- storeMeta引用会导致无限循环依赖stsTokenData即可
}, [storeMeta.stsTokenData]);
const handleRefreshFileList = async () => ossStore.loadObjectList().catch(e => toast.error(e.message));