[Permissions] Add userWorkspaceId to JWT token (#9954)
This information will be used to fetch a user's role and check their permissions
This commit is contained in:
1
packages/twenty-server/@types/express.d.ts
vendored
1
packages/twenty-server/@types/express.d.ts
vendored
@ -10,5 +10,6 @@ declare module 'express-serve-static-core' {
|
|||||||
workspaceId?: string;
|
workspaceId?: string;
|
||||||
workspaceMetadataVersion?: number;
|
workspaceMetadataVersion?: number;
|
||||||
workspaceMemberId?: string;
|
workspaceMemberId?: string;
|
||||||
|
userWorkspaceId?: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ export class AuthException extends CustomException {
|
|||||||
|
|
||||||
export enum AuthExceptionCode {
|
export enum AuthExceptionCode {
|
||||||
USER_NOT_FOUND = 'USER_NOT_FOUND',
|
USER_NOT_FOUND = 'USER_NOT_FOUND',
|
||||||
|
USER_WORKSPACE_NOT_FOUND = 'USER_WORKSPACE_NOT_FOUND',
|
||||||
EMAIL_NOT_VERIFIED = 'EMAIL_NOT_VERIFIED',
|
EMAIL_NOT_VERIFIED = 'EMAIL_NOT_VERIFIED',
|
||||||
CLIENT_NOT_FOUND = 'CLIENT_NOT_FOUND',
|
CLIENT_NOT_FOUND = 'CLIENT_NOT_FOUND',
|
||||||
WORKSPACE_NOT_FOUND = 'WORKSPACE_NOT_FOUND',
|
WORKSPACE_NOT_FOUND = 'WORKSPACE_NOT_FOUND',
|
||||||
|
|||||||
@ -29,11 +29,13 @@ import { EmailVerificationModule } from 'src/engine/core-modules/email-verificat
|
|||||||
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||||
import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module';
|
import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module';
|
||||||
|
import { GuardRedirectModule } from 'src/engine/core-modules/guard-redirect/guard-redirect.module';
|
||||||
import { JwtModule } from 'src/engine/core-modules/jwt/jwt.module';
|
import { JwtModule } from 'src/engine/core-modules/jwt/jwt.module';
|
||||||
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
|
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
|
||||||
import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module';
|
import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module';
|
||||||
import { WorkspaceSSOModule } from 'src/engine/core-modules/sso/sso.module';
|
import { WorkspaceSSOModule } from 'src/engine/core-modules/sso/sso.module';
|
||||||
import { WorkspaceSSOIdentityProvider } from 'src/engine/core-modules/sso/workspace-sso-identity-provider.entity';
|
import { WorkspaceSSOIdentityProvider } from 'src/engine/core-modules/sso/workspace-sso-identity-provider.entity';
|
||||||
|
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||||
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { UserModule } from 'src/engine/core-modules/user/user.module';
|
import { UserModule } from 'src/engine/core-modules/user/user.module';
|
||||||
@ -45,7 +47,6 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat
|
|||||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||||
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
|
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
|
||||||
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
|
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
|
||||||
import { GuardRedirectModule } from 'src/engine/core-modules/guard-redirect/guard-redirect.module';
|
|
||||||
|
|
||||||
import { AuthResolver } from './auth.resolver';
|
import { AuthResolver } from './auth.resolver';
|
||||||
|
|
||||||
@ -70,6 +71,7 @@ import { JwtAuthStrategy } from './strategies/jwt.auth.strategy';
|
|||||||
FeatureFlag,
|
FeatureFlag,
|
||||||
WorkspaceSSOIdentityProvider,
|
WorkspaceSSOIdentityProvider,
|
||||||
KeyValuePair,
|
KeyValuePair,
|
||||||
|
UserWorkspace,
|
||||||
],
|
],
|
||||||
'core',
|
'core',
|
||||||
),
|
),
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import {
|
|||||||
AuthExceptionCode,
|
AuthExceptionCode,
|
||||||
} from 'src/engine/core-modules/auth/auth.exception';
|
} from 'src/engine/core-modules/auth/auth.exception';
|
||||||
import { JwtPayload } from 'src/engine/core-modules/auth/types/auth-context.type';
|
import { JwtPayload } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||||
|
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
|
|
||||||
import { JwtAuthStrategy } from './jwt.auth.strategy';
|
import { JwtAuthStrategy } from './jwt.auth.strategy';
|
||||||
@ -11,6 +12,7 @@ describe('JwtAuthStrategy', () => {
|
|||||||
let strategy: JwtAuthStrategy;
|
let strategy: JwtAuthStrategy;
|
||||||
|
|
||||||
let workspaceRepository: any;
|
let workspaceRepository: any;
|
||||||
|
let userWorkspaceRepository: any;
|
||||||
let userRepository: any;
|
let userRepository: any;
|
||||||
let dataSourceService: any;
|
let dataSourceService: any;
|
||||||
let typeORMService: any;
|
let typeORMService: any;
|
||||||
@ -27,6 +29,10 @@ describe('JwtAuthStrategy', () => {
|
|||||||
findOne: jest.fn(async () => null),
|
findOne: jest.fn(async () => null),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
userWorkspaceRepository = {
|
||||||
|
findOne: jest.fn(async () => new UserWorkspace()),
|
||||||
|
};
|
||||||
|
|
||||||
// first we test the API_KEY case
|
// first we test the API_KEY case
|
||||||
it('should throw AuthException if type is API_KEY and workspace is not found', async () => {
|
it('should throw AuthException if type is API_KEY and workspace is not found', async () => {
|
||||||
const payload = {
|
const payload = {
|
||||||
@ -45,6 +51,7 @@ describe('JwtAuthStrategy', () => {
|
|||||||
dataSourceService,
|
dataSourceService,
|
||||||
workspaceRepository,
|
workspaceRepository,
|
||||||
{} as any,
|
{} as any,
|
||||||
|
userWorkspaceRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(strategy.validate(payload as JwtPayload)).rejects.toThrow(
|
await expect(strategy.validate(payload as JwtPayload)).rejects.toThrow(
|
||||||
@ -80,6 +87,7 @@ describe('JwtAuthStrategy', () => {
|
|||||||
dataSourceService,
|
dataSourceService,
|
||||||
workspaceRepository,
|
workspaceRepository,
|
||||||
{} as any,
|
{} as any,
|
||||||
|
userWorkspaceRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(strategy.validate(payload as JwtPayload)).rejects.toThrow(
|
await expect(strategy.validate(payload as JwtPayload)).rejects.toThrow(
|
||||||
@ -117,6 +125,7 @@ describe('JwtAuthStrategy', () => {
|
|||||||
dataSourceService,
|
dataSourceService,
|
||||||
workspaceRepository,
|
workspaceRepository,
|
||||||
{} as any,
|
{} as any,
|
||||||
|
userWorkspaceRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await strategy.validate(payload as JwtPayload);
|
const result = await strategy.validate(payload as JwtPayload);
|
||||||
@ -148,6 +157,7 @@ describe('JwtAuthStrategy', () => {
|
|||||||
dataSourceService,
|
dataSourceService,
|
||||||
workspaceRepository,
|
workspaceRepository,
|
||||||
userRepository,
|
userRepository,
|
||||||
|
userWorkspaceRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(strategy.validate(payload as JwtPayload)).rejects.toThrow(
|
await expect(strategy.validate(payload as JwtPayload)).rejects.toThrow(
|
||||||
@ -160,7 +170,7 @@ describe('JwtAuthStrategy', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be truthy if type is ACCESS, no jti, and user exist', async () => {
|
it('should throw AuthExceptionCode if type is ACCESS, no jti, and userWorkspace not found', async () => {
|
||||||
const payload = {
|
const payload = {
|
||||||
sub: 'sub-default',
|
sub: 'sub-default',
|
||||||
type: 'ACCESS',
|
type: 'ACCESS',
|
||||||
@ -174,6 +184,10 @@ describe('JwtAuthStrategy', () => {
|
|||||||
findOne: jest.fn(async () => ({ lastName: 'lastNameDefault' })),
|
findOne: jest.fn(async () => ({ lastName: 'lastNameDefault' })),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
userWorkspaceRepository = {
|
||||||
|
findOne: jest.fn(async () => null),
|
||||||
|
};
|
||||||
|
|
||||||
strategy = new JwtAuthStrategy(
|
strategy = new JwtAuthStrategy(
|
||||||
{} as any,
|
{} as any,
|
||||||
{} as any,
|
{} as any,
|
||||||
@ -181,10 +195,52 @@ describe('JwtAuthStrategy', () => {
|
|||||||
dataSourceService,
|
dataSourceService,
|
||||||
workspaceRepository,
|
workspaceRepository,
|
||||||
userRepository,
|
userRepository,
|
||||||
|
userWorkspaceRepository,
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(strategy.validate(payload as JwtPayload)).rejects.toThrow(
|
||||||
|
new AuthException('UserWorkspace not found', expect.any(String)),
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await strategy.validate(payload as JwtPayload);
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.code).toBe(AuthExceptionCode.USER_WORKSPACE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be truthy if type is ACCESS, no jti, and user and userWorkspace exist', async () => {
|
||||||
|
const payload = {
|
||||||
|
sub: 'sub-default',
|
||||||
|
type: 'ACCESS',
|
||||||
|
};
|
||||||
|
|
||||||
|
workspaceRepository = {
|
||||||
|
findOneBy: jest.fn(async () => new Workspace()),
|
||||||
|
};
|
||||||
|
|
||||||
|
userRepository = {
|
||||||
|
findOne: jest.fn(async () => ({ lastName: 'lastNameDefault' })),
|
||||||
|
};
|
||||||
|
|
||||||
|
userWorkspaceRepository = {
|
||||||
|
findOne: jest.fn(async () => ({
|
||||||
|
id: 'userWorkspaceId',
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
strategy = new JwtAuthStrategy(
|
||||||
|
{} as any,
|
||||||
|
{} as any,
|
||||||
|
typeORMService,
|
||||||
|
dataSourceService,
|
||||||
|
workspaceRepository,
|
||||||
|
userRepository,
|
||||||
|
userWorkspaceRepository,
|
||||||
);
|
);
|
||||||
|
|
||||||
const user = await strategy.validate(payload as JwtPayload);
|
const user = await strategy.validate(payload as JwtPayload);
|
||||||
|
|
||||||
expect(user.user?.lastName).toBe('lastNameDefault');
|
expect(user.user?.lastName).toBe('lastNameDefault');
|
||||||
|
expect(user.userWorkspaceId).toBe('userWorkspaceId');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
} from 'src/engine/core-modules/auth/types/auth-context.type';
|
} from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||||
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
||||||
|
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||||
@ -32,6 +33,8 @@ export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') {
|
|||||||
private readonly workspaceRepository: Repository<Workspace>,
|
private readonly workspaceRepository: Repository<Workspace>,
|
||||||
@InjectRepository(User, 'core')
|
@InjectRepository(User, 'core')
|
||||||
private readonly userRepository: Repository<User>,
|
private readonly userRepository: Repository<User>,
|
||||||
|
@InjectRepository(UserWorkspace, 'core')
|
||||||
|
private readonly userWorkspaceRepository: Repository<UserWorkspace>,
|
||||||
) {
|
) {
|
||||||
super({
|
super({
|
||||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||||
@ -117,7 +120,20 @@ export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { user, workspace };
|
const userWorkspace = await this.userWorkspaceRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id: payload.userWorkspaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!userWorkspace) {
|
||||||
|
throw new AuthException(
|
||||||
|
'UserWorkspace not found',
|
||||||
|
AuthExceptionCode.USER_WORKSPACE_NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { user, workspace, userWorkspaceId: userWorkspace.id };
|
||||||
}
|
}
|
||||||
|
|
||||||
async validate(payload: JwtPayload): Promise<AuthContext> {
|
async validate(payload: JwtPayload): Promise<AuthContext> {
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { EmailService } from 'src/engine/core-modules/email/email.service';
|
|||||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||||
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
||||||
import { SSOService } from 'src/engine/core-modules/sso/services/sso.service';
|
import { SSOService } from 'src/engine/core-modules/sso/services/sso.service';
|
||||||
|
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||||
@ -25,6 +26,7 @@ describe('AccessTokenService', () => {
|
|||||||
let userRepository: Repository<User>;
|
let userRepository: Repository<User>;
|
||||||
let workspaceRepository: Repository<Workspace>;
|
let workspaceRepository: Repository<Workspace>;
|
||||||
let twentyORMGlobalManager: TwentyORMGlobalManager;
|
let twentyORMGlobalManager: TwentyORMGlobalManager;
|
||||||
|
let userWorkspaceRepository: Repository<UserWorkspace>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
@ -63,6 +65,10 @@ describe('AccessTokenService', () => {
|
|||||||
provide: getRepositoryToken(Workspace, 'core'),
|
provide: getRepositoryToken(Workspace, 'core'),
|
||||||
useClass: Repository,
|
useClass: Repository,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: getRepositoryToken(UserWorkspace, 'core'),
|
||||||
|
useClass: Repository,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: EmailService,
|
provide: EmailService,
|
||||||
useValue: {},
|
useValue: {},
|
||||||
@ -92,6 +98,9 @@ describe('AccessTokenService', () => {
|
|||||||
twentyORMGlobalManager = module.get<TwentyORMGlobalManager>(
|
twentyORMGlobalManager = module.get<TwentyORMGlobalManager>(
|
||||||
TwentyORMGlobalManager,
|
TwentyORMGlobalManager,
|
||||||
);
|
);
|
||||||
|
userWorkspaceRepository = module.get<Repository<UserWorkspace>>(
|
||||||
|
getRepositoryToken(UserWorkspace, 'core'),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be defined', () => {
|
it('should be defined', () => {
|
||||||
@ -109,6 +118,7 @@ describe('AccessTokenService', () => {
|
|||||||
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
||||||
id: workspaceId,
|
id: workspaceId,
|
||||||
};
|
};
|
||||||
|
const mockUserWorkspace = { id: 'userWorkspaceId' };
|
||||||
const mockWorkspaceMember = { id: 'workspace-member-id' };
|
const mockWorkspaceMember = { id: 'workspace-member-id' };
|
||||||
const mockToken = 'mock-token';
|
const mockToken = 'mock-token';
|
||||||
|
|
||||||
@ -117,6 +127,9 @@ describe('AccessTokenService', () => {
|
|||||||
jest
|
jest
|
||||||
.spyOn(workspaceRepository, 'findOne')
|
.spyOn(workspaceRepository, 'findOne')
|
||||||
.mockResolvedValue(mockWorkspace as Workspace);
|
.mockResolvedValue(mockWorkspace as Workspace);
|
||||||
|
jest
|
||||||
|
.spyOn(userWorkspaceRepository, 'findOne')
|
||||||
|
.mockResolvedValue(mockUserWorkspace as UserWorkspace);
|
||||||
jest
|
jest
|
||||||
.spyOn(twentyORMGlobalManager, 'getRepositoryForWorkspace')
|
.spyOn(twentyORMGlobalManager, 'getRepositoryForWorkspace')
|
||||||
.mockResolvedValue({
|
.mockResolvedValue({
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import {
|
|||||||
} from 'src/engine/core-modules/auth/types/auth-context.type';
|
} from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||||
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
||||||
|
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { userValidator } from 'src/engine/core-modules/user/user.validate';
|
import { userValidator } from 'src/engine/core-modules/user/user.validate';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
@ -38,6 +39,8 @@ export class AccessTokenService {
|
|||||||
@InjectRepository(Workspace, 'core')
|
@InjectRepository(Workspace, 'core')
|
||||||
private readonly workspaceRepository: Repository<Workspace>,
|
private readonly workspaceRepository: Repository<Workspace>,
|
||||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||||
|
@InjectRepository(UserWorkspace, 'core')
|
||||||
|
private readonly userWorkspaceRepository: Repository<UserWorkspace>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async generateAccessToken(
|
async generateAccessToken(
|
||||||
@ -87,11 +90,18 @@ export class AccessTokenService {
|
|||||||
|
|
||||||
tokenWorkspaceMemberId = workspaceMember.id;
|
tokenWorkspaceMemberId = workspaceMember.id;
|
||||||
}
|
}
|
||||||
|
const userWorkspace = await this.userWorkspaceRepository.findOne({
|
||||||
|
where: {
|
||||||
|
userId: user.id,
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const jwtPayload: JwtPayload = {
|
const jwtPayload: JwtPayload = {
|
||||||
sub: user.id,
|
sub: user.id,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
workspaceMemberId: tokenWorkspaceMemberId,
|
workspaceMemberId: tokenWorkspaceMemberId,
|
||||||
|
userWorkspaceId: userWorkspace?.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -108,10 +118,10 @@ export class AccessTokenService {
|
|||||||
|
|
||||||
const decoded = await this.jwtWrapperService.decode(token);
|
const decoded = await this.jwtWrapperService.decode(token);
|
||||||
|
|
||||||
const { user, apiKey, workspace, workspaceMemberId } =
|
const { user, apiKey, workspace, workspaceMemberId, userWorkspaceId } =
|
||||||
await this.jwtStrategy.validate(decoded as JwtPayload);
|
await this.jwtStrategy.validate(decoded as JwtPayload);
|
||||||
|
|
||||||
return { user, apiKey, workspace, workspaceMemberId };
|
return { user, apiKey, workspace, workspaceMemberId, userWorkspaceId };
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateTokenByRequest(request: Request): Promise<AuthContext> {
|
async validateTokenByRequest(request: Request): Promise<AuthContext> {
|
||||||
|
|||||||
@ -12,15 +12,19 @@ import { RenewTokenService } from 'src/engine/core-modules/auth/token/services/r
|
|||||||
import { EmailModule } from 'src/engine/core-modules/email/email.module';
|
import { EmailModule } from 'src/engine/core-modules/email/email.module';
|
||||||
import { JwtModule } from 'src/engine/core-modules/jwt/jwt.module';
|
import { JwtModule } from 'src/engine/core-modules/jwt/jwt.module';
|
||||||
import { WorkspaceSSOModule } from 'src/engine/core-modules/sso/sso.module';
|
import { WorkspaceSSOModule } from 'src/engine/core-modules/sso/sso.module';
|
||||||
|
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||||
|
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||||
import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
JwtModule,
|
JwtModule,
|
||||||
TypeOrmModule.forFeature([User, AppToken, Workspace], 'core'),
|
TypeOrmModule.forFeature(
|
||||||
|
[User, AppToken, Workspace, UserWorkspace],
|
||||||
|
'core',
|
||||||
|
),
|
||||||
TypeORMModule,
|
TypeORMModule,
|
||||||
DataSourceModule,
|
DataSourceModule,
|
||||||
EmailModule,
|
EmailModule,
|
||||||
|
|||||||
@ -8,6 +8,7 @@ export type AuthContext = {
|
|||||||
apiKey?: ApiKeyWorkspaceEntity | null | undefined;
|
apiKey?: ApiKeyWorkspaceEntity | null | undefined;
|
||||||
workspaceMemberId?: string;
|
workspaceMemberId?: string;
|
||||||
workspace: Workspace;
|
workspace: Workspace;
|
||||||
|
userWorkspaceId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type JwtPayload = {
|
export type JwtPayload = {
|
||||||
@ -16,4 +17,5 @@ export type JwtPayload = {
|
|||||||
workspaceMemberId?: string;
|
workspaceMemberId?: string;
|
||||||
jti?: string;
|
jti?: string;
|
||||||
type?: WorkspaceTokenType;
|
type?: WorkspaceTokenType;
|
||||||
|
userWorkspaceId?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { ExecutionContext, createParamDecorator } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { getRequest } from 'src/utils/extract-request';
|
||||||
|
|
||||||
|
export const AuthUserWorkspaceId = createParamDecorator(
|
||||||
|
(data: unknown, ctx: ExecutionContext) => {
|
||||||
|
const request = getRequest(ctx);
|
||||||
|
|
||||||
|
return request.userWorkspaceId;
|
||||||
|
},
|
||||||
|
);
|
||||||
@ -27,6 +27,7 @@ export class JwtAuthGuard implements CanActivate {
|
|||||||
request.workspaceId = data.workspace.id;
|
request.workspaceId = data.workspace.id;
|
||||||
request.workspaceMetadataVersion = metadataVersion;
|
request.workspaceMetadataVersion = metadataVersion;
|
||||||
request.workspaceMemberId = data.workspaceMemberId;
|
request.workspaceMemberId = data.workspaceMemberId;
|
||||||
|
request.userWorkspaceId = data.userWorkspaceId;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user