merge fix/refresh-token
This commit is contained in:
parent
946d977db8
commit
69ff7a8ff7
3
.env
3
.env
@ -20,4 +20,5 @@ LDAP_ATTRIBUTE=
|
|||||||
API_SECRET=
|
API_SECRET=
|
||||||
API_TOKEN_TTL=
|
API_TOKEN_TTL=
|
||||||
API_CACHE_TTL=
|
API_CACHE_TTL=
|
||||||
COOKIE_TOKEN_NAME=token
|
COOKIE_TOKEN_NAME=token
|
||||||
|
COOKIE_TOKEN_MAX_AGE=
|
||||||
@ -71,7 +71,7 @@ export class AccountService {
|
|||||||
|
|
||||||
const payload: TokenPayload = {
|
const payload: TokenPayload = {
|
||||||
username: login,
|
username: login,
|
||||||
...omit(account.toJSON(), ['password']),
|
...omit(account.toJSON(), ['password', '_id', '__v']),
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.jwtService.sign(payload);
|
return this.jwtService.sign(payload);
|
||||||
|
|||||||
@ -3,29 +3,46 @@ import { env } from './config/env';
|
|||||||
import { Controller, Get, HttpStatus, Req, Res } from '@nestjs/common';
|
import { Controller, Get, HttpStatus, Req, Res } from '@nestjs/common';
|
||||||
import { ApiExcludeController } from '@nestjs/swagger';
|
import { ApiExcludeController } from '@nestjs/swagger';
|
||||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
|
import { cookieOptions } from 'src/config/cookie';
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
@ApiExcludeController()
|
@ApiExcludeController()
|
||||||
export class AppController {
|
export class AppController {
|
||||||
constructor(private readonly appService: AppService) {}
|
constructor(private readonly appService: AppService) {}
|
||||||
|
|
||||||
@Get('auth')
|
@Get('auth')
|
||||||
public async auth(@Req() req: FastifyRequest, @Res() reply: FastifyReply) {
|
public async auth(@Req() req: FastifyRequest, @Res() reply: FastifyReply) {
|
||||||
|
const token = req.cookies[env.COOKIE_TOKEN_NAME] || req.headers?.authorization?.split(' ')[1];
|
||||||
|
if (!token) return reply.status(HttpStatus.UNAUTHORIZED).send();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const token = req.cookies[env.COOKIE_TOKEN_NAME] || req.headers.authorization.split(' ')[1];
|
return this.handleDefaultCheck(req, reply, token);
|
||||||
|
} catch (error) {
|
||||||
|
const _err = error as Error;
|
||||||
|
const isTokenExpired = _err.name?.toLocaleLowerCase().includes('expired');
|
||||||
|
const refreshToken = req.headers['refresh-token'] === '1';
|
||||||
|
|
||||||
this.appService.checkToken(token);
|
if (isTokenExpired && refreshToken) return this.handleExpiredToken(req, reply, token);
|
||||||
|
|
||||||
reply.header('Authorization', `Bearer ${token}`);
|
return this.handleError(req, reply);
|
||||||
|
|
||||||
return reply.send();
|
|
||||||
} catch {
|
|
||||||
// if (error.name === 'TokenExpiredError') {
|
|
||||||
// const newToken = this.appService.refreshToken(token);
|
|
||||||
|
|
||||||
// return reply.setCookie(env.COOKIE_TOKEN_NAME, newToken, cookieOptions).send();
|
|
||||||
// }
|
|
||||||
|
|
||||||
return reply.status(HttpStatus.UNAUTHORIZED).send();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleDefaultCheck(req: FastifyRequest, reply: FastifyReply, token: string) {
|
||||||
|
this.appService.checkToken(token);
|
||||||
|
reply.header('Authorization', `Bearer ${token}`);
|
||||||
|
|
||||||
|
return reply.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleExpiredToken(req: FastifyRequest, reply: FastifyReply, token: string) {
|
||||||
|
const newToken = this.appService.refreshToken(token);
|
||||||
|
reply.header('Authorization', `Bearer ${newToken}`);
|
||||||
|
|
||||||
|
return reply.setCookie(env.COOKIE_TOKEN_NAME, newToken, cookieOptions).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleError(req: FastifyRequest, reply: FastifyReply) {
|
||||||
|
return reply.status(HttpStatus.UNAUTHORIZED).send();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { env } from 'src/config/env';
|
|||||||
|
|
||||||
export const cookieOptions: CookieSerializeOptions = {
|
export const cookieOptions: CookieSerializeOptions = {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
maxAge: env.API_TOKEN_TTL,
|
maxAge: env.COOKIE_TOKEN_MAX_AGE,
|
||||||
path: '/',
|
path: '/',
|
||||||
secure: true,
|
secure: true,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,6 +5,7 @@ const envSchema = z.object({
|
|||||||
API_PORT: z.number().optional().default(3001),
|
API_PORT: z.number().optional().default(3001),
|
||||||
API_SECRET: z.string(),
|
API_SECRET: z.string(),
|
||||||
API_TOKEN_TTL: z.string().transform((val) => Number.parseInt(val, 10)),
|
API_TOKEN_TTL: z.string().transform((val) => Number.parseInt(val, 10)),
|
||||||
|
COOKIE_TOKEN_MAX_AGE: z.string().transform((val) => Number.parseInt(val, 10)),
|
||||||
COOKIE_TOKEN_NAME: z.string().default('token'),
|
COOKIE_TOKEN_NAME: z.string().default('token'),
|
||||||
LDAP_ATTRIBUTE: z.string(),
|
LDAP_ATTRIBUTE: z.string(),
|
||||||
LDAP_BASE: z.string(),
|
LDAP_BASE: z.string(),
|
||||||
|
|||||||
@ -11,12 +11,14 @@ export class Account {
|
|||||||
@ApiResponseProperty()
|
@ApiResponseProperty()
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@Prop({ index: { unique: true }, required: true })
|
@Prop({ index: { unique: true }, required: true })
|
||||||
username: string;
|
public username: string;
|
||||||
|
|
||||||
@ApiResponseProperty()
|
@ApiResponseProperty()
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@Prop({ required: true })
|
@Prop({ required: true })
|
||||||
password: string;
|
public password: string;
|
||||||
|
|
||||||
|
readonly [key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AccountSchema = SchemaFactory.createForClass(Account);
|
export const AccountSchema = SchemaFactory.createForClass(Account);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user