introduce an authentication service and prepare user management

Tento commit je obsažen v:
Sven Czarnian
2022-11-03 01:30:27 +01:00
rodič ce17a29f7c
revize 58b98456ac
5 změnil soubory, kde provedl 144 přidání a 49 odebrání

Zobrazit soubor

@@ -11,13 +11,13 @@ import { ApiQuery } from '@nestjs/swagger';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { catchError, lastValueFrom, map } from 'rxjs';
import { AuthService } from './auth.service';
@Controller('auth')
export class AuthController {
constructor(
private config: ConfigService,
private httpService: HttpService,
private jwtService: JwtService,
private authService: AuthService,
) {}
@Get('/vatsim')
@@ -35,58 +35,15 @@ export class AuthController {
);
}
const token = await lastValueFrom(
this.httpService
.post(
`${this.config.get<string>(
'vatsim-auth.base-url',
)}/${this.config.get<string>('vatsim-auth.token-endpoint')}`,
{
grant_type: 'authorization_code',
client_id: this.config.get<string>('vatsim-auth.client-id'),
client_secret: this.config.get<string>('vatsim-auth.client-secret'),
redirect_uri: 'http://localhost:3000/auth/vatsim',
code,
},
)
.pipe(
map((response) => response.data.access_token),
catchError((err) => {
throw new HttpException(err.response.data, err.response.status);
}),
),
);
const token = await this.authService.login(code);
const userdata = await lastValueFrom(
this.httpService
.get(
`${this.config.get<string>(
'vatsim-auth.base-url',
)}/${this.config.get<string>('vatsim-auth.user-endpoint')}`,
{
headers: {
Authorization: `Bearer ${token}`,
Accept: 'application/json',
},
},
)
.pipe(
map((response) => response.data.data),
catchError((err) => {
throw new HttpException(err.response.data, err.response.status);
}),
),
);
if (userdata.oauth.token_valid) {
const payload = { username: userdata.cid, sub: token };
const accessToken = this.jwtService.sign(payload);
if (token !== undefined) {
return {
url: `${this.config.get<string>(
'frontend.base-url',
)}/${this.config.get<string>(
'frontend.login-endpoint',
)}?token=${accessToken}`,
)}?token=${token}`,
};
} else {
return {

Zobrazit soubor

@@ -2,8 +2,11 @@ import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
import { MongooseModule } from '@nestjs/mongoose';
import { AuthController } from './auth.controller';
import { UserSchema } from './models/user.model';
import { JwtStrategy } from './strategies/jwt.strategy';
import { AuthService } from './auth.service';
@Module({
imports: [
@@ -15,8 +18,9 @@ import { JwtStrategy } from './strategies/jwt.strategy';
signOptions: { expiresIn: '1h' },
}),
}),
MongooseModule.forFeature([{ name: 'user', schema: UserSchema }]),
],
providers: [JwtStrategy],
providers: [JwtStrategy, AuthService],
controllers: [AuthController],
})
export class AuthModule {}

18
src/auth/auth.service.spec.ts Normální soubor
Zobrazit soubor

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AuthService],
}).compile();
service = module.get<AuthService>(AuthService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

72
src/auth/auth.service.ts Normální soubor
Zobrazit soubor

@@ -0,0 +1,72 @@
import { HttpService } from '@nestjs/axios';
import { HttpException, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { catchError, lastValueFrom, map } from 'rxjs';
import { UserDocument } from './models/user.model';
@Injectable()
export class AuthService {
constructor(
@InjectModel('user')
private readonly userModel: Model<UserDocument>,
private config: ConfigService,
private httpService: HttpService,
private jwtService: JwtService,
) {}
async login(code: string): Promise<string> {
const token = await lastValueFrom(
this.httpService
.post(
`${this.config.get<string>(
'vatsim-auth.base-url',
)}/${this.config.get<string>('vatsim-auth.token-endpoint')}`,
{
grant_type: 'authorization_code',
client_id: this.config.get<string>('vatsim-auth.client-id'),
client_secret: this.config.get<string>('vatsim-auth.client-secret'),
redirect_uri: 'http://localhost:3000/auth/vatsim',
code,
},
)
.pipe(
map((response) => response.data.access_token),
catchError((err) => {
throw new HttpException(err.response.data, err.response.status);
}),
),
);
const userdata = await lastValueFrom(
this.httpService
.get(
`${this.config.get<string>(
'vatsim-auth.base-url',
)}/${this.config.get<string>('vatsim-auth.user-endpoint')}`,
{
headers: {
Authorization: `Bearer ${token}`,
Accept: 'application/json',
},
},
)
.pipe(
map((response) => response.data.data),
catchError((err) => {
throw new HttpException(err.response.data, err.response.status);
}),
),
);
if (userdata.oauth.token_valid) {
const payload = { username: userdata.cid, sub: token };
return this.jwtService.sign(payload);
}
return undefined;
}
}

44
src/auth/models/user.model.ts Normální soubor
Zobrazit soubor

@@ -0,0 +1,44 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
export type UserDocument = User & Document;
@Schema()
export class User {
@Prop({
required: true,
index: true,
type: String,
})
vatsimId: string;
@Prop({
type: String,
})
fullName: string;
@Prop({
required: true,
type: String,
})
vatsimToken: string;
@Prop({
type: String,
})
vatsimRefreshToken: string;
@Prop({
type: Boolean,
default: false,
})
administrator: boolean;
@Prop({
type: [String],
default: [],
})
airportConfigurationAccess: string[];
}
export const UserSchema = SchemaFactory.createForClass(User);