diff --git a/doc/sql/schema.sql b/doc/sql/schema.sql
index e3d2b5c..dc758dd 100644
--- a/doc/sql/schema.sql
+++ b/doc/sql/schema.sql
@@ -1,3 +1,52 @@
+CREATE TABLE verification_token
+(
+ identifier TEXT NOT NULL,
+ expires TIMESTAMPTZ NOT NULL,
+ token TEXT NOT NULL,
+
+ PRIMARY KEY (identifier, token)
+);
+
+CREATE TABLE accounts
+(
+ id SERIAL,
+ "userId" INTEGER NOT NULL,
+ type VARCHAR(255) NOT NULL,
+ provider VARCHAR(255) NOT NULL,
+ "providerAccountId" VARCHAR(255) NOT NULL,
+ refresh_token TEXT,
+ access_token TEXT,
+ expires_at BIGINT,
+ id_token TEXT,
+ scope TEXT,
+ session_state TEXT,
+ token_type TEXT,
+
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE sessions
+(
+ id SERIAL,
+ "userId" INTEGER NOT NULL,
+ expires TIMESTAMPTZ NOT NULL,
+ "sessionToken" VARCHAR(255) NOT NULL,
+
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE users
+(
+ id SERIAL,
+ name VARCHAR(255),
+ email VARCHAR(255),
+ password VARCHAR(255),
+ "emailVerified" TIMESTAMPTZ,
+ image TEXT,
+
+ PRIMARY KEY (id)
+);
+
-- ----------------------------
-- Table structure for picimpact_image
-- ----------------------------
@@ -72,5 +121,3 @@ INSERT INTO "public"."picimpact_config" VALUES (12, 'cdn_url', '', 'CDN 域名
INSERT INTO "public"."picimpact_config" VALUES (5, 'auth_key', 'picimpact', '权限 key,jwt 和 hash 都需要用到它。如果您更改了它,请自行生成新密码,默认值:picimpact', '2023-12-25 16:45:46.12813', NULL);
INSERT INTO "public"."picimpact_config" VALUES (4, 'alist_token', '', 'alist 令牌 ', '2023-12-25 16:45:08.661365', NULL);
INSERT INTO "public"."picimpact_config" VALUES (3, 'alist_url', '', 'AList 地址,如:https://alist.besscroft.com', '2023-12-25 16:44:55.289006', NULL);
-INSERT INTO "public"."picimpact_config" VALUES (1, 'username', 'admin', '系统用户账号,默认值:admin,单次登录有效期 24 小时。', '2023-12-25 16:44:29.653008', NULL);
-INSERT INTO "public"."picimpact_config" VALUES (2, 'password', '2a2a3d2b5dcef92937839896bcf07dc62605ebe2ac428f57ea061c734d950d075667654a5e130a9fee5b85512a98eac8138100f32a40953b8678243dbfc97297', '系统用户密码,默认值(666666)在 `.env.local` 文件中可查,如果需要更改密码,可在登录后进入后台自行生成后替换。', '2023-12-25 16:44:43.899401', NULL);
diff --git a/middleware.ts b/middleware.ts
new file mode 100644
index 0000000..f43c7ed
--- /dev/null
+++ b/middleware.ts
@@ -0,0 +1,7 @@
+import { auth } from '~/utils/lib/auth'
+
+export default auth;
+
+export const config = {
+ matcher: ["/admin/:path*"],
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index eccb483..979e4c3 100644
--- a/package.json
+++ b/package.json
@@ -9,10 +9,13 @@
"lint": "next lint"
},
"dependencies": {
+ "@auth/pg-adapter": "^0.7.2",
"@nextui-org/react": "^2.2.10",
"framer-motion": "^11.0.24",
"next": "^14.1.4",
+ "next-auth": "5.0.0-beta.16",
"next-themes": "^0.3.0",
+ "pg": "^8.11.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-responsive": "^10.0.0",
@@ -20,10 +23,12 @@
"sonner": "^1.4.41",
"swr": "^2.2.5",
"vaul": "^0.9.0",
+ "zod": "^3.22.4",
"zustand": "^4.5.2"
},
"devDependencies": {
"@types/node": "^20.12.2",
+ "@types/pg": "^8.11.4",
"@types/react": "^18.2.73",
"@types/react-dom": "^18.2.23",
"autoprefixer": "^10.4.19",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ff7abcb..96f1180 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -5,6 +5,9 @@ settings:
excludeLinksFromLockfile: false
dependencies:
+ '@auth/pg-adapter':
+ specifier: ^0.7.2
+ version: 0.7.2(pg@8.11.5)
'@nextui-org/react':
specifier: ^2.2.10
version: 2.2.10(@types/react@18.2.73)(framer-motion@11.0.24)(react-dom@18.2.0)(react@18.2.0)(tailwind-variants@0.2.1)(tailwindcss@3.4.3)
@@ -14,9 +17,15 @@ dependencies:
next:
specifier: ^14.1.4
version: 14.1.4(react-dom@18.2.0)(react@18.2.0)
+ next-auth:
+ specifier: 5.0.0-beta.16
+ version: 5.0.0-beta.16(next@14.1.4)(react@18.2.0)
next-themes:
specifier: ^0.3.0
version: 0.3.0(react-dom@18.2.0)(react@18.2.0)
+ pg:
+ specifier: ^8.11.5
+ version: 8.11.5
react:
specifier: ^18.2.0
version: 18.2.0
@@ -38,6 +47,9 @@ dependencies:
vaul:
specifier: ^0.9.0
version: 0.9.0(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
+ zod:
+ specifier: ^3.22.4
+ version: 3.22.4
zustand:
specifier: ^4.5.2
version: 4.5.2(@types/react@18.2.73)(react@18.2.0)
@@ -46,6 +58,9 @@ devDependencies:
'@types/node':
specifier: ^20.12.2
version: 20.12.2
+ '@types/pg':
+ specifier: ^8.11.4
+ version: 8.11.4
'@types/react':
specifier: ^18.2.73
version: 18.2.73
@@ -82,6 +97,65 @@ packages:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
+ /@auth/core@0.28.1:
+ resolution: {integrity: sha512-gvp74mypYZADpTlfGRp6HE0G3pIHWvtJpy+KZ+8FvY0cmlIpHog+jdMOdd29dQtLtN25kF2YbfHsesCFuGUQbg==}
+ peerDependencies:
+ '@simplewebauthn/browser': ^9.0.1
+ '@simplewebauthn/server': ^9.0.2
+ nodemailer: ^6.8.0
+ peerDependenciesMeta:
+ '@simplewebauthn/browser':
+ optional: true
+ '@simplewebauthn/server':
+ optional: true
+ nodemailer:
+ optional: true
+ dependencies:
+ '@panva/hkdf': 1.1.1
+ '@types/cookie': 0.6.0
+ cookie: 0.6.0
+ jose: 5.2.3
+ oauth4webapi: 2.10.4
+ preact: 10.11.3
+ preact-render-to-string: 5.2.3(preact@10.11.3)
+ dev: false
+
+ /@auth/core@0.28.2:
+ resolution: {integrity: sha512-Rlvu6yKa4bKbhQESMaEm6jHOY5ncIrsrQkC8tcwVQmf+cBLk7ReI9DIJS2O/WkIDoOwvM9PHiXTi5b+b/eyXxw==}
+ peerDependencies:
+ '@simplewebauthn/browser': ^9.0.1
+ '@simplewebauthn/server': ^9.0.2
+ nodemailer: ^6.8.0
+ peerDependenciesMeta:
+ '@simplewebauthn/browser':
+ optional: true
+ '@simplewebauthn/server':
+ optional: true
+ nodemailer:
+ optional: true
+ dependencies:
+ '@panva/hkdf': 1.1.1
+ '@types/cookie': 0.6.0
+ cookie: 0.6.0
+ jose: 5.2.3
+ oauth4webapi: 2.10.4
+ preact: 10.11.3
+ preact-render-to-string: 5.2.3(preact@10.11.3)
+ dev: false
+
+ /@auth/pg-adapter@0.7.2(pg@8.11.5):
+ resolution: {integrity: sha512-hhMflWXzkB1TVBZs/1zdgVHgnAkxL+xZrK5F3l44RQZ7ZAUoIvVXYKJva551wj0F11x04cpy+noeXg3a0jDnHw==}
+ peerDependencies:
+ pg: ^8
+ dependencies:
+ '@auth/core': 0.28.2
+ pg: 8.11.5
+ transitivePeerDependencies:
+ - '@simplewebauthn/browser'
+ - '@simplewebauthn/server'
+ - nodemailer
+ dev: false
+
/@babel/runtime@7.24.1:
resolution: {integrity: sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==}
engines: {node: '>=6.9.0'}
@@ -1643,6 +1717,10 @@ packages:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
+ /@panva/hkdf@1.1.1:
+ resolution: {integrity: sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==}
+ dev: false
+
/@pkgjs/parseargs@0.11.0:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@@ -2857,6 +2935,10 @@ packages:
tslib: 2.6.2
dev: false
+ /@types/cookie@0.6.0:
+ resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
+ dev: false
+
/@types/json5@0.0.29:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true
@@ -2867,6 +2949,14 @@ packages:
undici-types: 5.26.5
dev: true
+ /@types/pg@8.11.4:
+ resolution: {integrity: sha512-yw3Bwbda6vO+NvI1Ue/YKOwtl31AYvvd/e73O3V4ZkNzuGpTDndLSyc0dQRB2xrQqDePd20pEGIfqSp/GH3pRw==}
+ dependencies:
+ '@types/node': 20.12.2
+ pg-protocol: 1.6.1
+ pg-types: 4.0.2
+ dev: true
+
/@types/prop-types@15.7.12:
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
@@ -3302,6 +3392,11 @@ packages:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
+ /cookie@0.6.0:
+ resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@@ -4408,6 +4503,10 @@ packages:
resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
hasBin: true
+ /jose@5.2.3:
+ resolution: {integrity: sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==}
+ dev: false
+
/js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -4599,6 +4698,27 @@ packages:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true
+ /next-auth@5.0.0-beta.16(next@14.1.4)(react@18.2.0):
+ resolution: {integrity: sha512-dX2snB+ezN23tFzSes3n3uosT9iBf0eILPYWH/R2fd9n3ZzdMQlRzq7JIOPeS1aLc84IuRlyuyXyx9XmmZB6og==}
+ peerDependencies:
+ '@simplewebauthn/browser': ^9.0.1
+ '@simplewebauthn/server': ^9.0.2
+ next: ^14
+ nodemailer: ^6.6.5
+ react: ^18.2.0
+ peerDependenciesMeta:
+ '@simplewebauthn/browser':
+ optional: true
+ '@simplewebauthn/server':
+ optional: true
+ nodemailer:
+ optional: true
+ dependencies:
+ '@auth/core': 0.28.1
+ next: 14.1.4(react-dom@18.2.0)(react@18.2.0)
+ react: 18.2.0
+ dev: false
+
/next-themes@0.3.0(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==}
peerDependencies:
@@ -4661,6 +4781,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /oauth4webapi@2.10.4:
+ resolution: {integrity: sha512-DSoj8QoChzOCQlJkRmYxAJCIpnXFW32R0Uq7avyghIeB6iJq0XAblOD7pcq3mx4WEBDwMuKr0Y1qveCBleG2Xw==}
+ dev: false
+
/object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -4734,6 +4858,10 @@ packages:
es-object-atoms: 1.0.0
dev: true
+ /obuf@1.1.2:
+ resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
+ dev: true
+
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
@@ -4802,6 +4930,84 @@ packages:
engines: {node: '>=8'}
dev: true
+ /pg-cloudflare@1.1.1:
+ resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /pg-connection-string@2.6.4:
+ resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==}
+ dev: false
+
+ /pg-int8@1.0.1:
+ resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
+ engines: {node: '>=4.0.0'}
+
+ /pg-numeric@1.0.2:
+ resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /pg-pool@3.6.2(pg@8.11.5):
+ resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==}
+ peerDependencies:
+ pg: '>=8.0'
+ dependencies:
+ pg: 8.11.5
+ dev: false
+
+ /pg-protocol@1.6.1:
+ resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==}
+
+ /pg-types@2.2.0:
+ resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
+ engines: {node: '>=4'}
+ dependencies:
+ pg-int8: 1.0.1
+ postgres-array: 2.0.0
+ postgres-bytea: 1.0.0
+ postgres-date: 1.0.7
+ postgres-interval: 1.2.0
+ dev: false
+
+ /pg-types@4.0.2:
+ resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==}
+ engines: {node: '>=10'}
+ dependencies:
+ pg-int8: 1.0.1
+ pg-numeric: 1.0.2
+ postgres-array: 3.0.2
+ postgres-bytea: 3.0.0
+ postgres-date: 2.1.0
+ postgres-interval: 3.0.0
+ postgres-range: 1.1.4
+ dev: true
+
+ /pg@8.11.5:
+ resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==}
+ engines: {node: '>= 8.0.0'}
+ peerDependencies:
+ pg-native: '>=3.0.1'
+ peerDependenciesMeta:
+ pg-native:
+ optional: true
+ dependencies:
+ pg-connection-string: 2.6.4
+ pg-pool: 3.6.2(pg@8.11.5)
+ pg-protocol: 1.6.1
+ pg-types: 2.2.0
+ pgpass: 1.0.5
+ optionalDependencies:
+ pg-cloudflare: 1.1.1
+ dev: false
+
+ /pgpass@1.0.5:
+ resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
+ dependencies:
+ split2: 4.2.0
+ dev: false
+
/picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
@@ -4894,11 +5100,76 @@ packages:
picocolors: 1.0.0
source-map-js: 1.2.0
+ /postgres-array@2.0.0:
+ resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
+ engines: {node: '>=4'}
+ dev: false
+
+ /postgres-array@3.0.2:
+ resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /postgres-bytea@1.0.0:
+ resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /postgres-bytea@3.0.0:
+ resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==}
+ engines: {node: '>= 6'}
+ dependencies:
+ obuf: 1.1.2
+ dev: true
+
+ /postgres-date@1.0.7:
+ resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /postgres-date@2.1.0:
+ resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /postgres-interval@1.2.0:
+ resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ xtend: 4.0.2
+ dev: false
+
+ /postgres-interval@3.0.0:
+ resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /postgres-range@1.1.4:
+ resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==}
+ dev: true
+
+ /preact-render-to-string@5.2.3(preact@10.11.3):
+ resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==}
+ peerDependencies:
+ preact: '>=10'
+ dependencies:
+ preact: 10.11.3
+ pretty-format: 3.8.0
+ dev: false
+
+ /preact@10.11.3:
+ resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==}
+ dev: false
+
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
dev: true
+ /pretty-format@3.8.0:
+ resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
+ dev: false
+
/prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
dependencies:
@@ -5234,6 +5505,11 @@ packages:
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
engines: {node: '>=0.10.0'}
+ /split2@4.2.0:
+ resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
+ engines: {node: '>= 10.x'}
+ dev: false
+
/streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
@@ -5743,6 +6019,11 @@ packages:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
+ /xtend@4.0.2:
+ resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
+ engines: {node: '>=0.4'}
+ dev: false
+
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true
@@ -5757,6 +6038,10 @@ packages:
engines: {node: '>=10'}
dev: true
+ /zod@3.22.4:
+ resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
+ dev: false
+
/zustand@4.5.2(@types/react@18.2.73)(react@18.2.0):
resolution: {integrity: sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==}
engines: {node: '>=12.7.0'}
diff --git a/utils/lib/auth.ts b/utils/lib/auth.ts
new file mode 100644
index 0000000..54db8d9
--- /dev/null
+++ b/utils/lib/auth.ts
@@ -0,0 +1,93 @@
+import NextAuth from 'next-auth'
+import type { NextAuthConfig } from 'next-auth'
+import CredentialsProvider from 'next-auth/providers/credentials'
+import PostgresAdapter from '@auth/pg-adapter'
+import pool from '~/utils/lib/db'
+import { z } from 'zod'
+// import { toast } from 'sonner'
+
+const authConfig = {
+ secret: 'T7tQXKqqKjZrJhN62Z05AHY8qKGQKaG/4iqv0tKmEvw=',
+ adapter: PostgresAdapter(pool),
+ session: {
+ strategy: "jwt",
+ },
+ pages: {
+ signIn: "/login",
+ },
+ providers: [
+ CredentialsProvider({
+ id: "credentials",
+ name: "Credentials",
+ type: "credentials",
+ credentials: {
+ email: { label: "Email", type: "email", placeholder: "Email" },
+ password: { label: "Password", type: "password" }
+ },
+ async authorize(credentials, req) {
+ const parsedCredentials = z
+ .object({ email: z.string().email(), password: z.string().min(6) })
+ .safeParse(credentials);
+
+ if (parsedCredentials.success) {
+ const { email, password } = parsedCredentials.data;
+ // TODO 邮件和密码校验
+ console.log(email, password)
+
+ const user = await pool.query('SELECT * FROM users WHERE email = $1::text LIMIT 1', [`${email}`])
+
+ console.log(user.rowCount)
+ console.log(user.rows[0])
+ if (user.rowCount === 0) {
+ // toast.error('登录失败!', {duration: 1000})
+ return null;
+ }
+
+ // toast.success('登录成功!', {duration: 1000})
+ return user.rows[0];
+ }
+
+ console.log('Invalid credentials');
+ // toast.error('登录失败!', {duration: 1000})
+ return null;
+ }
+ })
+ ],
+ callbacks: {
+ async session({ token, session }) {
+ if (token) {
+ session.user = {
+ ...session.user,
+ id: session.user.id,
+ name: session.user.name,
+ email: session.user.email,
+ image: session.user.image,
+ }
+ }
+
+ return session
+ },
+ async jwt({ token, user }) {
+ const dbUser = await pool.query('SELECT * FROM users WHERE email = $1::text LIMIT 1', [`${user.email}`])
+
+ if (dbUser.rowCount === 0) {
+ token.id = Number(user?.id)
+ return token
+ }
+
+ return {
+ ...token,
+ id: dbUser.rows[0]?.id,
+ name: dbUser.rows[0]?.name,
+ email: dbUser.rows[0]?.email,
+ picture: dbUser.rows[0]?.image,
+ }
+ },
+ },
+} satisfies NextAuthConfig;
+
+export const {
+ handlers: { GET, POST },
+ auth,
+ signIn,
+} = NextAuth(authConfig)
\ No newline at end of file
diff --git a/utils/lib/db.ts b/utils/lib/db.ts
new file mode 100644
index 0000000..a466675
--- /dev/null
+++ b/utils/lib/db.ts
@@ -0,0 +1,14 @@
+import { Pool } from 'pg'
+
+const pool = new Pool({
+ host: process.env.POSTGRE_HOST,
+ port: process.env.POSTGRE_PORT,
+ database: process.env.POSTGRE_DATABASE,
+ user: process.env.POSTGRE_USERNAME,
+ password: process.env.POSTGRE_PASSWORD,
+ max: 20,
+ idleTimeoutMillis: 30000,
+ connectionTimeoutMillis: 2000,
+})
+
+export default pool;
\ No newline at end of file
diff --git a/utils/lib/session.ts b/utils/lib/session.ts
new file mode 100644
index 0000000..b71d3c5
--- /dev/null
+++ b/utils/lib/session.ts
@@ -0,0 +1,7 @@
+import { auth } from '~/utils/lib/auth'
+
+export async function getSession() {
+ const session = await auth()
+
+ return session
+}
\ No newline at end of file
diff --git a/utils/lib/userContext.ts b/utils/lib/userContext.ts
new file mode 100644
index 0000000..a9cce77
--- /dev/null
+++ b/utils/lib/userContext.ts
@@ -0,0 +1,7 @@
+import { auth } from '~/utils/lib/auth'
+
+export async function getCurrentUser() {
+ const session = await auth()
+
+ return session?.user
+}
\ No newline at end of file