mirror of https://github.com/fantasticit/think.git
feat: use cookie to authentication
parent
b28b4df011
commit
132c8ccd04
|
@ -36,6 +36,7 @@
|
|||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.13.2",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"date-fns": "^2.28.0",
|
||||
"express": "^4.17.2",
|
||||
"express-rate-limit": "^6.2.0",
|
||||
|
@ -64,6 +65,7 @@
|
|||
"@nestjs/cli": "^8.0.0",
|
||||
"@nestjs/schematics": "^8.0.0",
|
||||
"@nestjs/testing": "^8.0.0",
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/cron": "^2.0.0",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/jest": "27.0.2",
|
||||
|
|
|
@ -12,10 +12,13 @@ import {
|
|||
Patch,
|
||||
Post,
|
||||
Request,
|
||||
Res,
|
||||
UseGuards,
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { wrapResponse } from '@transforms/http-response.transform';
|
||||
import { Response as ExpressResponse } from 'express';
|
||||
|
||||
@Controller('user')
|
||||
export class UserController {
|
||||
|
@ -31,9 +34,16 @@ export class UserController {
|
|||
@UseInterceptors(ClassSerializerInterceptor)
|
||||
@Post('login')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
async login(@Body() user: LoginUserDto) {
|
||||
const res = await this.userService.login(user);
|
||||
return res;
|
||||
async login(@Body() user: LoginUserDto, @Res({ passthrough: true }) response: ExpressResponse) {
|
||||
const { user: data, token } = await this.userService.login(user);
|
||||
response.cookie('token', token, { httpOnly: true, sameSite: 'none', secure: true });
|
||||
return response.send(wrapResponse({ data: { ...data, token }, statusCode: HttpStatus.OK }));
|
||||
}
|
||||
|
||||
@Get('logout')
|
||||
async logout(@Res({ passthrough: true }) response: ExpressResponse) {
|
||||
response.cookie('token', '', { expires: new Date() });
|
||||
return;
|
||||
}
|
||||
|
||||
@UseInterceptors(ClassSerializerInterceptor)
|
||||
|
|
|
@ -253,6 +253,10 @@ export class WikiController {
|
|||
@UseGuards(WikiUserRoleGuard)
|
||||
@UseGuards(JwtGuard)
|
||||
async getWikiTocs(@Request() req, @Param('id') wikiId) {
|
||||
const sleep = (v) => {
|
||||
return new Promise((r) => setTimeout(r, v * 1000));
|
||||
};
|
||||
await sleep(4);
|
||||
return await this.wikiService.getWikiTocs(req.user, wikiId);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,13 +23,7 @@ export class DocumentAuthorityGuard implements CanActivate {
|
|||
}
|
||||
|
||||
const request = context.switchToHttp().getRequest();
|
||||
|
||||
let token = request.headers.authorization;
|
||||
|
||||
if (/Bearer/.test(token)) {
|
||||
token = token.split(' ').pop();
|
||||
}
|
||||
|
||||
const token = request?.cookies['token'];
|
||||
const user = this.jwtService.decode(token) as IUser;
|
||||
const { params, query, body } = request;
|
||||
const documentId = params?.id || params?.documentId || query?.id || query?.documentId || body?.documentId;
|
||||
|
|
|
@ -23,15 +23,8 @@ export class WikiUserRoleGuard implements CanActivate {
|
|||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const targetUserRole = this.reflector.get<WikiUserRole | null>(KEY, context.getHandler());
|
||||
|
||||
const request = context.switchToHttp().getRequest();
|
||||
|
||||
let token = request.headers.authorization;
|
||||
|
||||
if (/Bearer/.test(token)) {
|
||||
token = token.split(' ').pop();
|
||||
}
|
||||
|
||||
const token = request?.cookies['token'];
|
||||
const user = this.jwtService.decode(token) as IUser;
|
||||
|
||||
if (!user) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import { NestFactory } from '@nestjs/core';
|
|||
import { ValidationPipe } from '@pipes/validation.pipe';
|
||||
import { HttpResponseTransformInterceptor } from '@transforms/http-response.transform';
|
||||
import * as compression from 'compression';
|
||||
import * as cookieParser from 'cookie-parser';
|
||||
import * as express from 'express';
|
||||
import helmet from 'helmet';
|
||||
|
||||
|
@ -18,7 +19,13 @@ async function bootstrap() {
|
|||
const config = app.get(ConfigService);
|
||||
const port = config.get('server.port') || 5002;
|
||||
|
||||
app.enableCors();
|
||||
app.enableCors({
|
||||
// TODO: fixme
|
||||
origin: 'http://localhost:5001',
|
||||
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
|
||||
credentials: true,
|
||||
});
|
||||
app.use(cookieParser());
|
||||
app.use(compression());
|
||||
app.use(helmet());
|
||||
app.use(express.json());
|
||||
|
|
|
@ -10,6 +10,7 @@ import { PassportModule, PassportStrategy } from '@nestjs/passport';
|
|||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { getConfig } from '@think/config';
|
||||
import { Request as RequestType } from 'express';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
|
||||
const config = getConfig();
|
||||
|
@ -25,8 +26,14 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
|
|||
private readonly userService: UserService
|
||||
) {
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
ignoreExpiration: false,
|
||||
secretOrKey: jwtConfig.secretkey,
|
||||
jwtFromRequest: ExtractJwt.fromExtractors([
|
||||
(request: RequestType) => {
|
||||
const token = request?.cookies['token'];
|
||||
return token;
|
||||
},
|
||||
]),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ export class UserService {
|
|||
* @param user
|
||||
* @returns
|
||||
*/
|
||||
async login(user: LoginUserDto): Promise<OutUser & { token: string }> {
|
||||
async login(user: LoginUserDto): Promise<{ user: OutUser; token: string }> {
|
||||
const { name, password } = user;
|
||||
const existUser = await this.userRepo.findOne({ where: { name } });
|
||||
|
||||
|
@ -125,7 +125,7 @@ export class UserService {
|
|||
|
||||
const res = instanceToPlain(existUser) as OutUser;
|
||||
const token = this.jwtService.sign(res);
|
||||
return Object.assign(res, { token });
|
||||
return { user: res, token };
|
||||
}
|
||||
|
||||
async validateUser(user: UserEntity) {
|
||||
|
|
|
@ -6,6 +6,15 @@ interface Response<T> {
|
|||
data: T;
|
||||
}
|
||||
|
||||
export function wrapResponse({ statusCode, data }) {
|
||||
return {
|
||||
statusCode,
|
||||
message: null,
|
||||
success: true,
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class HttpResponseTransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
|
||||
intercept(context: ExecutionContext, next: CallHandler<T>): Observable<Response<T>> {
|
||||
|
@ -13,17 +22,8 @@ export class HttpResponseTransformInterceptor<T> implements NestInterceptor<T, R
|
|||
map((data) => {
|
||||
const ctx = context.switchToHttp();
|
||||
const response = ctx.getResponse();
|
||||
// const request = ctx.getRequest();
|
||||
// const url = request.originalUrl;
|
||||
const statusCode = response.statusCode;
|
||||
const res = {
|
||||
statusCode,
|
||||
message: null,
|
||||
success: true,
|
||||
data,
|
||||
};
|
||||
// console.info(url, res);
|
||||
return res;
|
||||
return wrapResponse({ data, statusCode });
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue