diff --git a/package.json b/package.json index 643023c..d93777f 100644 --- a/package.json +++ b/package.json @@ -30,13 +30,15 @@ "@nestjs/passport": "^7.1.5", "@nestjs/platform-express": "^7.6.15", "@nestjs/typeorm": "7.1.5", + "@types/passport-jwt": "^3.0.5", "@types/passport-kakao": "^0.2.0", "@types/passport-naver": "^0.2.0", "dotenv": "^8.5.1", "mongoose": "^5.12.7", "passport": "^0.4.1", - "passport-kakao": "1.0.1", "passport-google-oauth20": "^2.0.0", + "passport-jwt": "^4.0.0", + "passport-kakao": "1.0.1", "passport-local": "^1.0.0", "passport-naver": "^1.0.6", "reflect-metadata": "^0.1.13", diff --git a/src/common/middlewares/auth.ts b/src/common/middlewares/auth.ts new file mode 100644 index 0000000..fb2b25b --- /dev/null +++ b/src/common/middlewares/auth.ts @@ -0,0 +1,44 @@ +// import { Injectable, CanActivate, ExecutionContext, HttpException, HttpStatus } from '@nestjs/common'; +// import { Observable } from 'rxjs'; +// import { JwtService } from '@nestjs/jwt'; + +// @Injectable() +// export class AuthGuard implements CanActivate { +// canActivate( +// context: ExecutionContext, +// ): boolean | Promise | Observable { +// const request = context.switchToHttp().getRequest(); + +// const { access_token } = request.headers; + +// if (access_token === undefined) { +// // 토큰이 전송되지 않았다면 +// throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED); +// } + +// request.user = this.validationToken(access_token); + +// return true; +// } + +// validationToken(access_token:String):String{ +// try { +// const verify: string = jwt.verify(token, getProcessEnv('JWT_SECRET')) as string; +// return verify; +// } catch (error) { +// switch (error.message) { +// // 토큰에 대한 오류를 판단합니다. +// case 'INVALID_TOKEN': +// case 'TOKEN_IS_ARRAY': +// case 'NO_USER': +// throw new HttpException('NotFound',HttpStatus.NOT_FOUND); + +// case 'EXPIRED_TOKEN': +// throw new HttpException('NonAuthoritativeInformation',HttpStatus.NON_AUTHORITATIVE_INFORMATION); + +// default: +// throw new HttpException('InternalServerError', HttpStatus.INTERNAL_SERVER_ERROR); +// } +// } +// } +// } \ No newline at end of file diff --git a/src/models/auth/auth.controller.ts b/src/models/auth/auth.controller.ts index 17cbfb0..8c44e3f 100644 --- a/src/models/auth/auth.controller.ts +++ b/src/models/auth/auth.controller.ts @@ -1,7 +1,6 @@ -import { Controller, Get, Req, UseGuards } from '@nestjs/common'; +import { Controller, Get, Post, Req, Res, UseGuards, NotFoundException } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { AuthService } from './auth.service'; - @Controller('auth') export class AuthController { constructor(private readonly authService: AuthService) {} @@ -38,12 +37,24 @@ export class AuthController { @Get('login/naver/callback') @UseGuards(AuthGuard('naver')) - naverauthredirect(@Req() req) { - return this.authService.naverLogin(req); + naverauthredirect(@Req() req, @Res() res) { + const returndata = this.authService.naverLogin(req,res); + return returndata; } - @Get('login/naver/check') - navercheck(@Req() req) { - return this.authService.naverCheck(req); + //db에 잘들어갔는지 check하는 라우터 : DB 전체 조회 + // @Get('login/naver/check') + // navercheck(@Req() req) { + // return this.authService.naverCheck(req); + // } + + // 토큰 validation check하는 라우터 + + @Post('login/naver/token') + @UseGuards(AuthGuard('jwt')) + navertokenvalid(@Req() req){ + return req.user; } + + } diff --git a/src/models/auth/auth.module.ts b/src/models/auth/auth.module.ts index 698202f..8d46d3d 100644 --- a/src/models/auth/auth.module.ts +++ b/src/models/auth/auth.module.ts @@ -7,6 +7,7 @@ import { MongooseModule } from '@nestjs/mongoose'; import { UserSchema } from './entities/auth.model'; import { MongoModule } from '../../providers/database/mongo/mongo.module'; import { Kakaostrategy } from './passport/kakao.strategy'; +import { JwtModule } from '@nestjs/jwt'; @Module({ imports: [ @@ -14,6 +15,10 @@ import { Kakaostrategy } from './passport/kakao.strategy'; HttpModule, MongoModule, MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]), + JwtModule.register({ + secret: 'dsc-ai-chatbot', + signOptions: { expiresIn: 3600 }, + }), ], controllers: [AuthController], providers: [AuthService, GoogleStrategy, NaverStartegy, Kakaostrategy], diff --git a/src/models/auth/auth.service.ts b/src/models/auth/auth.service.ts index e0dea47..d7238d0 100644 --- a/src/models/auth/auth.service.ts +++ b/src/models/auth/auth.service.ts @@ -12,6 +12,7 @@ import { Model, FilterQuery } from 'mongoose'; import { User } from './entities/auth.model'; import { LoginUserDTO } from './dto/login.dto'; import { MongoService } from '../../providers/database/mongo/mongo.service'; +import { JwtService } from '@nestjs/jwt'; @Injectable() export class AuthService { @@ -19,6 +20,7 @@ export class AuthService { @InjectModel('User') private readonly userModel: Model, private readonly http: HttpService, // @InjectRepository(UserEntity) // private readonly userRepository: Repository, private readonly mongoservice: MongoService, + private jwtService: JwtService, ) {} googleLogin(req: any) { @@ -34,22 +36,36 @@ export class AuthService { return this.mongoservice.create(req.user, this.userModel); } - naverLogin(req): Promise | NotFoundException { + naverLogin(req, res): Promise | NotFoundException { + //social 로그인이 되지 않은 경우 : 네이버에 아이디가 없을 때 if (!req.user) { return new NotFoundException('No user from naver'); } + + //위의 조건을 통과했다면 서비스를 사용할 수 있기에 + //토큰을 발급하고 쿠키에 Token을 추가한다 + const Token = this.getToken(req.user); + console.log(Token); + res.cookie('Authorization',`${Token}`); + + //몽고db에 유저 정보가 있는지 조회한다 const alreadyuser = this.mongoservice.findOne( { id: `${req.user.id}` }, this.userModel, ); return alreadyuser.then((data) => { + //이미 서비스를 한 번 이용해서 DB에 정보가 있는 경우 if (data) { console.log(data); return data; - } else { + } + //처음 서비스를 사용해서 회원가입 되는 경우 + else { console.log('create!!'); - return this.mongoservice.create(req.user, this.userModel); + this.mongoservice.create(req.user, this.userModel); + return data; + // return this.mongoservice.create(req.user, this.userModel); } }); } @@ -71,21 +87,10 @@ export class AuthService { dupliCheck(user: User) { return true; } - //아래는 몽고 db 관련 메소드라 추후에 모듈화 할 것이다 - // async findOne(userFilterQuery:FilterQuery):Promise{ - // return this.userModel.findOne(userFilterQuery); - // } - // async find(usersFilterQuery:FilterQuery):Promise{ - // return this.userModel.find(usersFilterQuery); - // } - - // async create(user:User): Promise { - // const newUser = new this.userModel(user); - // return newUser.save() - // } + getToken(user: User){ + const payload = { username: user.email , sub: user.id}; + return this.jwtService.sign(payload); + } - // async findOneAndUpdate(userFilterQuery: FilterQuery, user: Partial): Promise{ - // return this.userModel.findOneAndUpdate(userFilterQuery, user); - // } } diff --git a/src/models/auth/passport/jwt.strategy.ts b/src/models/auth/passport/jwt.strategy.ts new file mode 100644 index 0000000..b802956 --- /dev/null +++ b/src/models/auth/passport/jwt.strategy.ts @@ -0,0 +1,31 @@ +import { Strategy } from 'passport-jwt'; +import { PassportStrategy } from '@nestjs/passport'; +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; + +const fromAuthCookie = function () { + return function (request) { + let token = null; + if (request && request.cookies ) { + token = request.cookies['Authorization']; + } + return token; + } +} + +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor( + private readonly config: ConfigService + ) { + super({ + jwtFromRequest: fromAuthCookie(), + ignoreExpiration: true, + secretOrKey: 'dsc-ai-chatbot', + }); + } + + async validate(payload: any) { + return { userid: payload.sub, email: payload.username }; + } +} \ No newline at end of file diff --git a/src/models/auth/passport/naver.strategy.ts b/src/models/auth/passport/naver.strategy.ts index b6792c8..78397b5 100644 --- a/src/models/auth/passport/naver.strategy.ts +++ b/src/models/auth/passport/naver.strategy.ts @@ -30,8 +30,8 @@ export class NaverStartegy extends PassportStrategy(Strategy, 'naver') { // 추후에 체크했는데 아직 리프레시 토큰이 살아서 // 계속 로그인 이후 정보를 제대로 받지 못함 // 그래서 우선 주석 처리함 - // email : _profile.email, - email: 'jawoon@dsc.com', + email: _profile.email, + // email: "hubigo97@naver.com", age: _profile.age, accountType: 'Naver', nickName: ' ', diff --git a/yarn.lock b/yarn.lock index 5881f2a..7ea63d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -661,7 +661,7 @@ "@nestjs/jwt@^7.2.0": version "7.2.0" - resolved "https://registry.npmjs.org/@nestjs/jwt/-/jwt-7.2.0.tgz" + resolved "https://registry.yarnpkg.com/@nestjs/jwt/-/jwt-7.2.0.tgz#d55d15c861b3e0d67a852cbe6131b14c85246852" integrity sha512-uOTqYmWNpu+oS/MrdYjrWXtKGV4HkCYmAEVEFPP/KfiP/7K6fNy+boLllE6cnqESAXh9u0CLa1noAAavs+LHEQ== dependencies: "@types/jsonwebtoken" "8.5.0" @@ -920,6 +920,13 @@ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/jsonwebtoken@*": + version "8.5.2" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.2.tgz#eb71c717b3b8681bb85fbd2950c9c4c5d4506748" + integrity sha512-X8BOCkp+WJVNYCYIBugREtVZa4Y09Or9HDx6xqRZem5F8jJV8FuJgNessXyMuv9+U8pjnvdezASwU28uw+1scw== + dependencies: + "@types/node" "*" + "@types/jsonwebtoken@8.5.0": version "8.5.0" resolved "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz" @@ -955,6 +962,15 @@ resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/passport-jwt@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/passport-jwt/-/passport-jwt-3.0.5.tgz#bb0b412130f2739bc223180634295d8d6f767df4" + integrity sha512-O6zZ4WKzQUwg3OU0MnOA2AIEQ6KfHyGdLoi4fqBLyb+kV7miGKNA2KNJRtiq45EsQ2QEDO8rKqORjXpWV7UJNg== + dependencies: + "@types/express" "*" + "@types/jsonwebtoken" "*" + "@types/passport-strategy" "*" + "@types/passport-kakao@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@types/passport-kakao/-/passport-kakao-0.2.0.tgz#633d57eec9443b797d67fa18815212c0af2388d4" @@ -971,6 +987,14 @@ "@types/express" "*" "@types/passport" "*" +"@types/passport-strategy@*": + version "0.2.35" + resolved "https://registry.yarnpkg.com/@types/passport-strategy/-/passport-strategy-0.2.35.tgz#e52f5212279ea73f02d9b06af67efe9cefce2d0c" + integrity sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g== + dependencies: + "@types/express" "*" + "@types/passport" "*" + "@types/passport@*": version "1.0.6" resolved "https://registry.npmjs.org/@types/passport/-/passport-1.0.6.tgz" @@ -4023,7 +4047,7 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonwebtoken@8.5.1: +jsonwebtoken@8.5.1, jsonwebtoken@^8.2.0: version "8.5.1" resolved "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== @@ -4860,6 +4884,14 @@ passport-google-oauth20@^2.0.0: dependencies: passport-oauth2 "1.x.x" +passport-jwt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.0.tgz#7f0be7ba942e28b9f5d22c2ebbb8ce96ef7cf065" + integrity sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg== + dependencies: + jsonwebtoken "^8.2.0" + passport-strategy "^1.0.0" + passport-kakao@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/passport-kakao/-/passport-kakao-1.0.1.tgz#e0593558afc0aa6244fc298be676b259f62b5e7a" @@ -4920,7 +4952,7 @@ passport-oauth@^1.0.0: passport-oauth1 "1.x.x" passport-oauth2 "1.x.x" -passport-strategy@1.x.x: +passport-strategy@1.x.x, passport-strategy@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz" integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=