feat: 添加飞书以及github登录
This commit is contained in:
parent
946be43558
commit
219afa0353
10
.env
10
.env
|
|
@ -3,4 +3,12 @@ SERVER_HOST='192.144.32.178'
|
|||
SERVER_PORT=3306
|
||||
SERVER_USER='root'
|
||||
PASSWORD='lichao1314'
|
||||
DB_NAME='auth_db'
|
||||
DB_NAME='auth_db'
|
||||
|
||||
GITHUB_CLIENT_ID=Ov23lihk723FlNAwlFg6
|
||||
GITHUB_CLIENT_SECRET=b839f50bba1f006ffdd43fb73c5ae221a54e1e2e
|
||||
GITHUB_CALLBACK_URL=http://localhost:3030/auth/github/callback
|
||||
|
||||
|
||||
FEISHU_APP_ID=cli_a66a897f687a5013
|
||||
FEISHU_APP_SECRET=s106GAbbCZk66OcHN69Rng5TaLK6fiH2
|
||||
|
|
|
|||
|
|
@ -29,12 +29,16 @@
|
|||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/typeorm": "^10.0.2",
|
||||
"@types/bcrypt": "^5.0.2",
|
||||
"@types/passport-github2": "^1.2.9",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"axios": "^1.7.9",
|
||||
"bcrypt": "^5.1.1",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"dotenv": "^16.4.7",
|
||||
"install": "^0.13.0",
|
||||
"mysql2": "^3.12.0",
|
||||
"passport": "^0.7.0",
|
||||
"passport-github2": "^0.1.12",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
|
|
|
|||
100
pnpm-lock.yaml
100
pnpm-lock.yaml
|
|
@ -16,13 +16,16 @@ specifiers:
|
|||
'@types/express': ^4.17.17
|
||||
'@types/jest': ^29.5.2
|
||||
'@types/node': ^20.3.1
|
||||
'@types/passport-github2': ^1.2.9
|
||||
'@types/passport-jwt': ^4.0.1
|
||||
'@types/supertest': ^6.0.0
|
||||
'@types/uuid': ^10.0.0
|
||||
'@typescript-eslint/eslint-plugin': ^6.0.0
|
||||
'@typescript-eslint/parser': ^6.0.0
|
||||
axios: ^1.7.9
|
||||
bcrypt: ^5.1.1
|
||||
bcryptjs: ^2.4.3
|
||||
dotenv: ^16.4.7
|
||||
eslint: ^8.42.0
|
||||
eslint-config-prettier: ^9.0.0
|
||||
eslint-plugin-prettier: ^5.0.0
|
||||
|
|
@ -30,6 +33,7 @@ specifiers:
|
|||
jest: ^29.5.0
|
||||
mysql2: ^3.12.0
|
||||
passport: ^0.7.0
|
||||
passport-github2: ^0.1.12
|
||||
passport-jwt: ^4.0.1
|
||||
passport-local: ^1.0.0
|
||||
prettier: ^3.0.0
|
||||
|
|
@ -55,12 +59,16 @@ dependencies:
|
|||
'@nestjs/platform-express': 10.4.15_5u4hn6whjn5aawl2edmluzh4i4
|
||||
'@nestjs/typeorm': 10.0.2_5ay6scu5luhdsc23ie3iqrw3sm
|
||||
'@types/bcrypt': 5.0.2
|
||||
'@types/passport-github2': 1.2.9
|
||||
'@types/uuid': 10.0.0
|
||||
axios: 1.7.9
|
||||
bcrypt: 5.1.1
|
||||
bcryptjs: 2.4.3
|
||||
dotenv: 16.4.7
|
||||
install: 0.13.0
|
||||
mysql2: 3.12.0
|
||||
passport: 0.7.0
|
||||
passport-github2: 0.1.12
|
||||
passport-jwt: 4.0.1
|
||||
passport-local: 1.0.0
|
||||
reflect-metadata: 0.1.14
|
||||
|
|
@ -1210,13 +1218,11 @@ packages:
|
|||
dependencies:
|
||||
'@types/connect': 3.4.38
|
||||
'@types/node': 20.17.12
|
||||
dev: true
|
||||
|
||||
/@types/connect/3.4.38:
|
||||
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
|
||||
dependencies:
|
||||
'@types/node': 20.17.12
|
||||
dev: true
|
||||
|
||||
/@types/cookiejar/2.1.5:
|
||||
resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==}
|
||||
|
|
@ -1247,7 +1253,6 @@ packages:
|
|||
'@types/qs': 6.9.17
|
||||
'@types/range-parser': 1.2.7
|
||||
'@types/send': 0.17.4
|
||||
dev: true
|
||||
|
||||
/@types/express/4.17.21:
|
||||
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
|
||||
|
|
@ -1256,7 +1261,6 @@ packages:
|
|||
'@types/express-serve-static-core': 4.19.6
|
||||
'@types/qs': 6.9.17
|
||||
'@types/serve-static': 1.15.7
|
||||
dev: true
|
||||
|
||||
/@types/graceful-fs/4.1.9:
|
||||
resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
|
||||
|
|
@ -1266,7 +1270,6 @@ packages:
|
|||
|
||||
/@types/http-errors/2.0.4:
|
||||
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
|
||||
dev: true
|
||||
|
||||
/@types/istanbul-lib-coverage/2.0.6:
|
||||
resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
|
||||
|
|
@ -1306,13 +1309,26 @@ packages:
|
|||
|
||||
/@types/mime/1.3.5:
|
||||
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
|
||||
dev: true
|
||||
|
||||
/@types/node/20.17.12:
|
||||
resolution: {integrity: sha512-vo/wmBgMIiEA23A/knMfn/cf37VnuF52nZh5ZoW0GWt4e4sxNquibrMRJ7UQsA06+MBx9r/H1jsI9grYjQCQlw==}
|
||||
dependencies:
|
||||
undici-types: 6.19.8
|
||||
|
||||
/@types/oauth/0.9.6:
|
||||
resolution: {integrity: sha512-H9TRCVKBNOhZZmyHLqFt9drPM9l+ShWiqqJijU1B8P3DX3ub84NjxDuy+Hjrz+fEca5Kwip3qPMKNyiLgNJtIA==}
|
||||
dependencies:
|
||||
'@types/node': 20.17.12
|
||||
dev: false
|
||||
|
||||
/@types/passport-github2/1.2.9:
|
||||
resolution: {integrity: sha512-/nMfiPK2E6GKttwBzwj0Wjaot8eHrM57hnWxu52o6becr5/kXlH/4yE2v2rh234WGvSgEEzIII02Nc5oC5xEHA==}
|
||||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
'@types/passport': 1.0.17
|
||||
'@types/passport-oauth2': 1.4.17
|
||||
dev: false
|
||||
|
||||
/@types/passport-jwt/4.0.1:
|
||||
resolution: {integrity: sha512-Y0Ykz6nWP4jpxgEUYq8NoVZeCQPo1ZndJLfapI249g1jHChvRfZRO/LS3tqu26YgAS/laI1qx98sYGz0IalRXQ==}
|
||||
dependencies:
|
||||
|
|
@ -1320,6 +1336,14 @@ packages:
|
|||
'@types/passport-strategy': 0.2.38
|
||||
dev: true
|
||||
|
||||
/@types/passport-oauth2/1.4.17:
|
||||
resolution: {integrity: sha512-ODiAHvso6JcWJ6ZkHHroVp05EHGhqQN533PtFNBkg8Fy5mERDqsr030AX81M0D69ZcaMvhF92SRckEk2B0HYYg==}
|
||||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
'@types/oauth': 0.9.6
|
||||
'@types/passport': 1.0.17
|
||||
dev: false
|
||||
|
||||
/@types/passport-strategy/0.2.38:
|
||||
resolution: {integrity: sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==}
|
||||
dependencies:
|
||||
|
|
@ -1331,15 +1355,12 @@ packages:
|
|||
resolution: {integrity: sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==}
|
||||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
dev: true
|
||||
|
||||
/@types/qs/6.9.17:
|
||||
resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==}
|
||||
dev: true
|
||||
|
||||
/@types/range-parser/1.2.7:
|
||||
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
|
||||
dev: true
|
||||
|
||||
/@types/semver/7.5.8:
|
||||
resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
|
||||
|
|
@ -1350,7 +1371,6 @@ packages:
|
|||
dependencies:
|
||||
'@types/mime': 1.3.5
|
||||
'@types/node': 20.17.12
|
||||
dev: true
|
||||
|
||||
/@types/serve-static/1.15.7:
|
||||
resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==}
|
||||
|
|
@ -1358,7 +1378,6 @@ packages:
|
|||
'@types/http-errors': 2.0.4
|
||||
'@types/node': 20.17.12
|
||||
'@types/send': 0.17.4
|
||||
dev: true
|
||||
|
||||
/@types/stack-utils/2.0.3:
|
||||
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
|
||||
|
|
@ -1839,13 +1858,22 @@ packages:
|
|||
|
||||
/asynckit/0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
dev: true
|
||||
|
||||
/aws-ssl-profiles/1.1.2:
|
||||
resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==}
|
||||
engines: {node: '>= 6.0.0'}
|
||||
dev: false
|
||||
|
||||
/axios/1.7.9:
|
||||
resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.9
|
||||
form-data: 4.0.1
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/babel-jest/29.7.0_@babel+core@7.26.0:
|
||||
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
|
|
@ -1927,6 +1955,11 @@ packages:
|
|||
/base64-js/1.5.1:
|
||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||
|
||||
/base64url/3.0.1:
|
||||
resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
dev: false
|
||||
|
||||
/bcrypt/5.1.1:
|
||||
resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
|
@ -2239,7 +2272,6 @@ packages:
|
|||
engines: {node: '>= 0.8'}
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
dev: true
|
||||
|
||||
/commander/2.20.3:
|
||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||
|
|
@ -2426,7 +2458,6 @@ packages:
|
|||
/delayed-stream/1.0.0:
|
||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
dev: true
|
||||
|
||||
/delegates/1.0.0:
|
||||
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
|
||||
|
|
@ -2951,6 +2982,16 @@ packages:
|
|||
resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
|
||||
dev: true
|
||||
|
||||
/follow-redirects/1.15.9:
|
||||
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
debug: '*'
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/foreground-child/3.3.0:
|
||||
resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
|
||||
engines: {node: '>=14'}
|
||||
|
|
@ -2988,7 +3029,6 @@ packages:
|
|||
asynckit: 0.4.0
|
||||
combined-stream: 1.0.8
|
||||
mime-types: 2.1.35
|
||||
dev: true
|
||||
|
||||
/formidable/2.1.2:
|
||||
resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==}
|
||||
|
|
@ -4438,6 +4478,10 @@ packages:
|
|||
set-blocking: 2.0.0
|
||||
dev: false
|
||||
|
||||
/oauth/0.10.0:
|
||||
resolution: {integrity: sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q==}
|
||||
dev: false
|
||||
|
||||
/object-assign/4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
@ -4567,6 +4611,13 @@ packages:
|
|||
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
/passport-github2/0.1.12:
|
||||
resolution: {integrity: sha512-3nPUCc7ttF/3HSP/k9sAXjz3SkGv5Nki84I05kSQPo01Jqq1NzJACgMblCK0fGcv9pKCG/KXU3AJRDGLqHLoIw==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
dependencies:
|
||||
passport-oauth2: 1.8.0
|
||||
dev: false
|
||||
|
||||
/passport-jwt/4.0.1:
|
||||
resolution: {integrity: sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==}
|
||||
dependencies:
|
||||
|
|
@ -4581,6 +4632,17 @@ packages:
|
|||
passport-strategy: 1.0.0
|
||||
dev: false
|
||||
|
||||
/passport-oauth2/1.8.0:
|
||||
resolution: {integrity: sha512-cjsQbOrXIDE4P8nNb3FQRCCmJJ/utnFKEz2NX209f7KOHPoX18gF7gBzBbLLsj2/je4KrgiwLLGjf0lm9rtTBA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
dependencies:
|
||||
base64url: 3.0.1
|
||||
oauth: 0.10.0
|
||||
passport-strategy: 1.0.0
|
||||
uid2: 0.0.4
|
||||
utils-merge: 1.0.1
|
||||
dev: false
|
||||
|
||||
/passport-strategy/1.0.0:
|
||||
resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
|
@ -4710,6 +4772,10 @@ packages:
|
|||
forwarded: 0.2.0
|
||||
ipaddr.js: 1.9.1
|
||||
|
||||
/proxy-from-env/1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
dev: false
|
||||
|
||||
/punycode/2.3.1:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
|
|
@ -5567,6 +5633,10 @@ packages:
|
|||
dependencies:
|
||||
'@lukeed/csprng': 1.1.0
|
||||
|
||||
/uid2/0.0.4:
|
||||
resolution: {integrity: sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==}
|
||||
dev: false
|
||||
|
||||
/undici-types/6.19.8:
|
||||
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
describe('AppController', () => {
|
||||
let appController: AppController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const app: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
}).compile();
|
||||
|
||||
appController = app.get<AppController>(AppController);
|
||||
});
|
||||
|
||||
describe('root', () => {
|
||||
it('should return "Hello World!"', () => {
|
||||
expect(appController.getHello()).toBe('Hello World!');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -5,6 +5,8 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
|
|||
import { AppService } from './app.service';
|
||||
import { UserModule } from './user/user.module';
|
||||
import { User } from './user/entities/user.entity';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { LarkModule } from './lark/lark.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
|
@ -25,6 +27,8 @@ import { User } from './user/entities/user.entity';
|
|||
}),
|
||||
TypeOrmModule.forFeature([User]),
|
||||
UserModule,
|
||||
AuthModule,
|
||||
LarkModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import { Controller, Get, Req, Res, UseGuards } from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { Response } from 'express';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
@Get('github')
|
||||
@UseGuards(AuthGuard('github'))
|
||||
async githubLogin() {
|
||||
// GitHub 登录重定向
|
||||
}
|
||||
|
||||
@Get('github/callback')
|
||||
@UseGuards(AuthGuard('github'))
|
||||
async githubCallback(@Req() req, @Res() res: Response) {
|
||||
const user = req.user;
|
||||
|
||||
// 构造前端 URL,附带用户信息或 Token
|
||||
const frontendUrl = `http://localhost:8000/?username=${user.username}&email=${user.email}`;
|
||||
// 重定向到前端
|
||||
return res.redirect(frontendUrl);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { GitHubStrategy } from './github.strategy';
|
||||
|
||||
@Module({
|
||||
imports: [PassportModule],
|
||||
controllers: [AuthController],
|
||||
providers: [GitHubStrategy],
|
||||
})
|
||||
export class AuthModule {}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { Strategy } from 'passport-github2';
|
||||
|
||||
@Injectable()
|
||||
export class GitHubStrategy extends PassportStrategy(Strategy, 'github') {
|
||||
constructor() {
|
||||
super({
|
||||
clientID: process.env.GITHUB_CLIENT_ID, // 从环境变量加载
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET,
|
||||
callbackURL: process.env.GITHUB_CALLBACK_URL, // 回调 URL
|
||||
scope: ['user:email'], // 需要的权限
|
||||
});
|
||||
}
|
||||
|
||||
async validate(accessToken: string, refreshToken: string, profile: any) {
|
||||
// 返回用户信息,或者直接处理用户登录逻辑
|
||||
const { id, username, emails } = profile;
|
||||
return {
|
||||
id,
|
||||
username,
|
||||
email: emails?.[0]?.value || null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { Controller, Get, Query, Res } from '@nestjs/common';
|
||||
import { LarkService } from './lark.service';
|
||||
import { Response } from 'express';
|
||||
|
||||
@Controller('lark')
|
||||
export class LarkController {
|
||||
constructor(private readonly larkService: LarkService) {}
|
||||
|
||||
@Get('login')
|
||||
async login(@Query('redirectUri') redirectUri: string, @Res() res: Response) {
|
||||
const loginUrl = await this.larkService.getLoginUrl(redirectUri);
|
||||
return res.redirect(loginUrl);
|
||||
}
|
||||
|
||||
@Get('callback')
|
||||
async callback(@Query('code') code: string, @Res() res: Response) {
|
||||
if (!code) {
|
||||
return res.status(400).send('Authorization code is missing');
|
||||
}
|
||||
|
||||
const tokenData = await this.larkService.getAccessToken(code);
|
||||
|
||||
if (tokenData && tokenData.code === 0) {
|
||||
const user = tokenData.data;
|
||||
return res.json({ message: 'Login successful', user });
|
||||
} else {
|
||||
return res.status(400).send('Failed to retrieve access token');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { LarkService } from './lark.service';
|
||||
import { LarkController } from './lark.controller';
|
||||
|
||||
@Module({
|
||||
controllers: [LarkController],
|
||||
providers: [LarkService],
|
||||
})
|
||||
export class LarkModule {}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import axios from 'axios';
|
||||
|
||||
@Injectable()
|
||||
export class LarkService {
|
||||
private readonly appId = process.env.FEISHU_APP_ID;
|
||||
private readonly appSecret = process.env.FEISHU_APP_SECRET;
|
||||
|
||||
async getLoginUrl(redirectUri: string): Promise<string> {
|
||||
return `https://open.feishu.cn/open-apis/authen/v1/index?app_id=${this.appId}&redirect_uri=${encodeURIComponent(
|
||||
redirectUri,
|
||||
)}`;
|
||||
}
|
||||
|
||||
async getAccessToken(authCode: string): Promise<any> {
|
||||
const url = 'https://open.feishu.cn/open-apis/authen/v1/access_token';
|
||||
const data = {
|
||||
grant_type: 'authorization_code',
|
||||
code: authCode,
|
||||
app_id: this.appId,
|
||||
app_secret: this.appSecret,
|
||||
};
|
||||
|
||||
const response = await axios.post(url, data);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,9 @@ import { NestFactory } from '@nestjs/core';
|
|||
import { AppModule } from './app.module';
|
||||
import * as mysql from 'mysql2/promise';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import * as dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
async function bootstrap() {
|
||||
// 启动 Nest 应用
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UserController } from './user.controller';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
describe('UserController', () => {
|
||||
let controller: UserController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [UserController],
|
||||
providers: [UserService],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<UserController>(UserController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue