From e2b8f86c74871ea21fa3d26a577c53fbe92fb390 Mon Sep 17 00:00:00 2001 From: Drakthor475 Date: Tue, 21 Oct 2025 14:01:53 -0600 Subject: [PATCH] jwt --- package-lock.json | 265 +++++++++++++++++++++++- package.json | 5 + src/app.module.ts | 4 +- src/auth/auth.controller.spec.ts | 18 ++ src/auth/auth.controller.ts | 24 +++ src/auth/auth.guard.ts | 6 + src/auth/auth.module.ts | 23 ++ src/auth/auth.service.spec.ts | 18 ++ src/auth/auth.service.ts | 55 +++++ src/auth/dto/login.dto.ts | 12 ++ src/auth/jwt.strategy.ts | 19 ++ src/usuarios/dto/create-usuario.dto.ts | 18 +- src/usuarios/entities/usuario.entity.ts | 3 +- src/usuarios/usuarios.controller.ts | 2 +- src/usuarios/usuarios.service.ts | 36 +++- 15 files changed, 493 insertions(+), 15 deletions(-) create mode 100644 src/auth/auth.controller.spec.ts create mode 100644 src/auth/auth.controller.ts create mode 100644 src/auth/auth.guard.ts create mode 100644 src/auth/auth.module.ts create mode 100644 src/auth/auth.service.spec.ts create mode 100644 src/auth/auth.service.ts create mode 100644 src/auth/dto/login.dto.ts create mode 100644 src/auth/jwt.strategy.ts diff --git a/package-lock.json b/package-lock.json index 5e703c1..b733054 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,12 +11,17 @@ "dependencies": { "@nestjs/common": "^11.1.6", "@nestjs/core": "^11.0.1", + "@nestjs/jwt": "^11.0.1", "@nestjs/mapped-types": "*", + "@nestjs/passport": "^11.0.5", "@nestjs/platform-express": "^11.0.1", "@nestjs/typeorm": "^11.0.0", + "argon2": "^0.44.0", "class-transformer": "0.5.1", "class-validator": "0.14.2", "mysql2": "^3.15.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", "typeor": "^1.2.0", @@ -788,6 +793,12 @@ "tslib": "^2.4.0" } }, + "node_modules/@epic-web/invariant": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz", + "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==", + "license": "MIT" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", @@ -2400,6 +2411,19 @@ } } }, + "node_modules/@nestjs/jwt": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-11.0.1.tgz", + "integrity": "sha512-HXSsc7SAnCnjA98TsZqrE7trGtHDnYXWp4Ffy6LwSmck1QvbGYdMzBquXofX5l6tIRpeY4Qidl2Ti2CVG77Pdw==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "9.0.10", + "jsonwebtoken": "9.0.2" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0" + } + }, "node_modules/@nestjs/mapped-types": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz", @@ -2420,6 +2444,16 @@ } } }, + "node_modules/@nestjs/passport": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-11.0.5.tgz", + "integrity": "sha512-ulQX6mbjlws92PIM15Naes4F4p2JoxGnIJuUsdXQPT+Oo2sqQmENEZXM7eYuimocfHnKlcfZOuyzbA33LwUlOQ==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "passport": "^0.5.0 || ^0.6.0 || ^0.7.0" + } + }, "node_modules/@nestjs/platform-express": { "version": "11.1.6", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.6.tgz", @@ -2657,6 +2691,15 @@ "@noble/hashes": "^1.1.5" } }, + "node_modules/@phc/format": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@phc/format/-/format-1.0.0.tgz", + "integrity": "sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2955,6 +2998,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -2969,11 +3022,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.18.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.11.tgz", "integrity": "sha512-Gd33J2XIrXurb+eT2ktze3rJAfAp9ZNjlBdh4SVgyrKEOADwCbdUDaK7QgJno8Ue4kcajscsKqu6n8OBG3hhCQ==", - "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -4032,6 +4090,22 @@ "devOptional": true, "license": "MIT" }, + "node_modules/argon2": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.44.0.tgz", + "integrity": "sha512-zHPGN3S55sihSQo0dBbK0A5qpi2R31z7HZDZnry3ifOyj8bZZnpZND2gpmhnRGO1V/d555RwBqIK5W4Mrmv3ig==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@phc/format": "^1.0.0", + "cross-env": "^10.0.0", + "node-addon-api": "^8.5.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">=16.17.0" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -4369,6 +4443,12 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -4919,6 +4999,23 @@ "devOptional": true, "license": "MIT" }, + "node_modules/cross-env": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", + "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", + "license": "MIT", + "dependencies": { + "@epic-web/invariant": "^1.0.0", + "cross-spawn": "^7.0.6" + }, + "bin": { + "cross-env": "dist/bin/cross-env.js", + "cross-env-shell": "dist/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -5124,6 +5221,15 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -7553,6 +7659,49 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -7656,6 +7805,42 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -7670,6 +7855,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -8109,6 +8300,15 @@ "dev": true, "license": "MIT" }, + "node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, "node_modules/node-emoji": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", @@ -8119,6 +8319,17 @@ "lodash": "^4.17.21" } }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -8368,6 +8579,42 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -8443,6 +8690,11 @@ "node": ">=8" } }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -8961,7 +9213,6 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -10412,7 +10663,6 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "devOptional": true, "license": "MIT" }, "node_modules/universalify": { @@ -10516,6 +10766,15 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/uuid": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", diff --git a/package.json b/package.json index 9636ed8..d8fe952 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,17 @@ "dependencies": { "@nestjs/common": "^11.1.6", "@nestjs/core": "^11.0.1", + "@nestjs/jwt": "^11.0.1", "@nestjs/mapped-types": "*", + "@nestjs/passport": "^11.0.5", "@nestjs/platform-express": "^11.0.1", "@nestjs/typeorm": "^11.0.0", + "argon2": "^0.44.0", "class-transformer": "0.5.1", "class-validator": "0.14.2", "mysql2": "^3.15.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", "typeor": "^1.2.0", diff --git a/src/app.module.ts b/src/app.module.ts index 24cb228..350e497 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -4,6 +4,7 @@ import { AppService } from './app.service'; import {ConfigModule} from '@nestjs/config' import { TypeOrmModule } from '@nestjs/typeorm'; import { UsuariosModule } from './usuarios/usuarios.module'; +import { AuthModule } from './auth/auth.module'; @@ -26,7 +27,8 @@ import { UsuariosModule } from './usuarios/usuarios.module'; }), - UsuariosModule + UsuariosModule, + AuthModule ], controllers: [], providers: [AppService], diff --git a/src/auth/auth.controller.spec.ts b/src/auth/auth.controller.spec.ts new file mode 100644 index 0000000..27a31e6 --- /dev/null +++ b/src/auth/auth.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { AuthController } from './auth.controller'; + +describe('AuthController', () => { + let controller: AuthController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [AuthController], + }).compile(); + + controller = module.get(AuthController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts new file mode 100644 index 0000000..0481f50 --- /dev/null +++ b/src/auth/auth.controller.ts @@ -0,0 +1,24 @@ +import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common'; +import { AuthService } from './auth.service'; +import { CreateUsuarioDto } from 'src/usuarios/dto/create-usuario.dto'; +import { LoginDto } from './dto/login.dto'; + + +@Controller('auth') +export class AuthController { + constructor( private readonly authService:AuthService){} + @Post("registro") + registro(@Body() registroDto:CreateUsuarioDto ){ + return this.authService.registro(registroDto); + + } + @Post("login") + login(@Body() loginDto:LoginDto){ + return this.authService.login(loginDto); + } + + + + + +} diff --git a/src/auth/auth.guard.ts b/src/auth/auth.guard.ts new file mode 100644 index 0000000..92b15a9 --- /dev/null +++ b/src/auth/auth.guard.ts @@ -0,0 +1,6 @@ +import { Injectable } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; + +@Injectable() +export class JwtAuthGuard extends AuthGuard('jwt'){} + diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts new file mode 100644 index 0000000..f9f1d3a --- /dev/null +++ b/src/auth/auth.module.ts @@ -0,0 +1,23 @@ +import { Module } from '@nestjs/common'; +import { AuthController } from './auth.controller'; +import { AuthService } from './auth.service'; +import { UsuariosModule } from 'src/usuarios/usuarios.module'; +import { JwtModule } from '@nestjs/jwt'; +import { PassportModule } from '@nestjs/passport'; +import { JwtStrategy } from './jwt.strategy'; + +@Module({ + imports:[UsuariosModule, + JwtModule, + PassportModule, + JwtModule.register({ + global:true, + secret: process.env.JWT, + signOptions:{expiresIn:"1d"}, + + }), + ], + controllers: [AuthController], + providers: [AuthService,JwtStrategy] +}) +export class AuthModule {} diff --git a/src/auth/auth.service.spec.ts b/src/auth/auth.service.spec.ts new file mode 100644 index 0000000..800ab66 --- /dev/null +++ b/src/auth/auth.service.spec.ts @@ -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); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts new file mode 100644 index 0000000..3751301 --- /dev/null +++ b/src/auth/auth.service.ts @@ -0,0 +1,55 @@ +import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common'; +import { UsuariosService } from 'src/usuarios/usuarios.service'; +import * as argon2 from 'argon2'; +import { LoginDto } from './dto/login.dto'; +import { CreateUsuarioDto } from 'src/usuarios/dto/create-usuario.dto'; +import { JwtService } from '@nestjs/jwt'; + +@Injectable() +export class AuthService { + constructor( + private readonly usuarioService:UsuariosService, + private readonly jwtService:JwtService + ){} + async registro({nombre, contraseña,tipoUsuario}: CreateUsuarioDto){ + const usuario= await this.usuarioService.findOneByName(nombre) + if(usuario){ + throw new BadRequestException("Nombre de usuario ya existente"); + } + const hashedContraseña= await argon2.hash(contraseña) ; + await this.usuarioService.create({ + nombre, + contraseña:hashedContraseña, + tipoUsuario + }); + return{ + message:"Usuario registrado exitosamente " }; + } + async login({nombre, contraseña}:LoginDto){ + const usuario= await this.usuarioService.findOneByName(nombre) + if(!usuario){ + throw new UnauthorizedException("Usuario no encontrado"); + + } + const contraseñaValida= await argon2.verify(contraseña, usuario.contraseña); + if(!contraseñaValida){ + throw new UnauthorizedException("Contraseña invalida"); + + } + const dataUser={ + id:usuario.id_usuario, + nombre:usuario.nombre, + tipoUsuario:usuario.tipoUsuario.id_tipo_usuario} + const token=await this.jwtService.sign(dataUser) + return{ + token:token, + }; + } + + + + + + + +} diff --git a/src/auth/dto/login.dto.ts b/src/auth/dto/login.dto.ts new file mode 100644 index 0000000..6c2a18a --- /dev/null +++ b/src/auth/dto/login.dto.ts @@ -0,0 +1,12 @@ +import { Transform } from "class-transformer"; +import { IsString, MinLength } from "class-validator"; +export class LoginDto{ + @IsString() + nombre:string; + + @IsString() + @MinLength(5) + @Transform(({value})=>value.trim()) + contraseña:string + +} \ No newline at end of file diff --git a/src/auth/jwt.strategy.ts b/src/auth/jwt.strategy.ts new file mode 100644 index 0000000..f792d56 --- /dev/null +++ b/src/auth/jwt.strategy.ts @@ -0,0 +1,19 @@ +import { PassportStrategy } from "@nestjs/passport"; +import{ExtractJwt,Strategy} from 'passport-jwt' + +export class JwtStrategy extends PassportStrategy(Strategy){ + constructor(){ + super({ + jwtFromRequest:ExtractJwt.fromAuthHeaderAsBearerToken(), + ignoreExpiration:false, + secretOrKey:process.env.JWT + }); + } + async validate(dataUser:any){ + return { + id: dataUser.id, + nombre: dataUser.nombre, + tipoUsuario: dataUser.tipoUsuario, + }; + } +} \ No newline at end of file diff --git a/src/usuarios/dto/create-usuario.dto.ts b/src/usuarios/dto/create-usuario.dto.ts index d7960fe..33a48f7 100644 --- a/src/usuarios/dto/create-usuario.dto.ts +++ b/src/usuarios/dto/create-usuario.dto.ts @@ -1 +1,17 @@ -export class CreateUsuarioDto {} +import { Transform } from "class-transformer" +import { IsInt, IsString, MinLength} from "class-validator" + +export class CreateUsuarioDto { +@IsString() +nombre:string + +@IsString() +@MinLength(5) +@Transform(({value})=>value.trim()) +contraseña:string + +@IsInt() +tipoUsuario:number + + +} diff --git a/src/usuarios/entities/usuario.entity.ts b/src/usuarios/entities/usuario.entity.ts index b899f79..ff49675 100644 --- a/src/usuarios/entities/usuario.entity.ts +++ b/src/usuarios/entities/usuario.entity.ts @@ -11,6 +11,7 @@ export class Usuario { @Column({length:100,nullable:true}) contraseña:string + @ManyToOne(()=>Tipo_Usuario,tipoUsuario=>tipoUsuario.usuarios ) tipoUsuario:Tipo_Usuario; @@ -22,7 +23,7 @@ export class Tipo_Usuario{ @PrimaryGeneratedColumn() id_tipo_usuario:number - @Column({nullable:true}) + @Column({length:50, nullable:true}) tipo_usuario:string @OneToMany(()=>Usuario,usuarios=>usuarios.tipoUsuario) diff --git a/src/usuarios/usuarios.controller.ts b/src/usuarios/usuarios.controller.ts index a016b2e..14e6681 100644 --- a/src/usuarios/usuarios.controller.ts +++ b/src/usuarios/usuarios.controller.ts @@ -11,7 +11,7 @@ export class UsuariosController { create(@Body() createUsuarioDto: CreateUsuarioDto) { return this.usuariosService.create(createUsuarioDto); } - + @Get() findAll() { return this.usuariosService.findAll(); diff --git a/src/usuarios/usuarios.service.ts b/src/usuarios/usuarios.service.ts index ac6192c..ec482ea 100644 --- a/src/usuarios/usuarios.service.ts +++ b/src/usuarios/usuarios.service.ts @@ -1,26 +1,46 @@ import { Injectable } from '@nestjs/common'; import { CreateUsuarioDto } from './dto/create-usuario.dto'; import { UpdateUsuarioDto } from './dto/update-usuario.dto'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Usuario } from './entities/usuario.entity'; +import { Repository } from 'typeorm'; @Injectable() export class UsuariosService { - create(createUsuarioDto: CreateUsuarioDto) { - return 'This action adds a new usuario'; + constructor( + @InjectRepository(Usuario) + private readonly usuarioRepository: Repository + ){} + async create(createUsuarioDto: CreateUsuarioDto) { + + let user= await this.usuarioRepository.create({ + nombre:createUsuarioDto.nombre, + contraseña:createUsuarioDto.contraseña, + tipoUsuario:{ + id_tipo_usuario:createUsuarioDto.tipoUsuario + } + }) + + return await this.usuarioRepository.save(user); } + async remove(id:number) { + return await this.usuarioRepository.delete(id); + } + async findOneByName(nombre: string) { + return await this.usuarioRepository.findOne({where:{nombre}}); + } + + findAll() { return `This action returns all usuarios`; } - findOne(id: number) { - return `This action returns a #${id} usuario`; - } + update(id: number, updateUsuarioDto: UpdateUsuarioDto) { return `This action updates a #${id} usuario`; } - remove(id: number) { - return `This action removes a #${id} usuario`; - } + }