feat: 后端用户密码哈希存储

This commit is contained in:
539943419 committed 2025-02-07 23:02:38 +08:00
1 parent 6e0a416422
commit 315916d027
10 files changed
+49 -30

No files matched your search

+2 -2
View File
@@ -2,7 +2,7 @@
# 接下来的计划 # 接下来的计划
- 用户密码哈希存储 - 用户密码哈希存储(👌)
- 文章表增加对最后编辑时间的支持与对加密的支持 - 文章表增加对最后编辑时间的支持与对加密的支持(没啥用感觉)
- 美化markdown的渲染 (👌) - 美化markdown的渲染 (👌)
- 迁移仓库到gitea (👌) - 迁移仓库到gitea (👌)
+9
View File
@@ -56,6 +56,15 @@ export default function useFetch() {
'Authorization': `Bearer ${userStore.token}` 'Authorization': `Bearer ${userStore.token}`
} }
}), }),
deletePost: (id: number) => $fetch('/api/posts/deletePost', {
body: {
id
},
method: 'POST',
headers: {
'Authorization': `Bearer ${userStore.token}`
}
})
}, },
user: { user: {
login: (body: { login: (body: {
+4 -8
View File
@@ -39,7 +39,7 @@ type resType = {
} & postItem } & postItem
const { post: { getPost, updatePost, uploadPost } } = useFetch() const { post: { getPost, updatePost, uploadPost, deletePost } } = useFetch()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
@@ -86,12 +86,7 @@ const handleClickDelete = async () => {
} }
) )
try { try {
const response = await $fetch('/api/posts/deletePost', { const response = await deletePost(id.value)
method: 'POST',
body: {
id: id.value
}
})
ElMessage({ ElMessage({
type: 'success', type: 'success',
message: '删除文章完成', message: '删除文章完成',
@@ -99,7 +94,8 @@ const handleClickDelete = async () => {
const store = useDefaultStore() const store = useDefaultStore()
store.deleteCache('posts') store.deleteCache('posts')
router.back() router.back()
} catch { } catch(e) {
console.error(e)
ElMessage({ ElMessage({
type: 'error', type: 'error',
message: '删除失败', message: '删除失败',
+3 -3
View File
@@ -1,4 +1,3 @@
// import { defineEventHandler, readBody, createError } from 'h3';
import bcrypt from 'bcryptjs'; import bcrypt from 'bcryptjs';
import BetterSqlite3 from 'better-sqlite3'; import BetterSqlite3 from 'better-sqlite3';
@@ -10,9 +9,10 @@ export default defineEventHandler(async (event) => {
// 查询用户 // 查询用户
const userDB = BetterSqlite3('./userData/db/user.db'); const userDB = BetterSqlite3('./userData/db/user.db');
const user: any = userDB.prepare('SELECT * FROM user WHERE username = ?').get(username); const user: any = userDB.prepare('SELECT * FROM user WHERE username = ?').get(username);
if (!user || password !== user.password) { const authRes = await authUser(username, password);
if(!authRes){
userDB.close(); userDB.close();
throw createError({ statusCode: 401, statusMessage: 'Invalid username or password' }); throw createError({ statusCode: 401, statusMessage: 'Username or password is incorrect' });
} }
// 更新最后登录时间 // 更新最后登录时间
+4
View File
@@ -10,6 +10,10 @@ export default defineEventHandler(async (event) => {
try { try {
// 验证旧的 Token // 验证旧的 Token
const decoded = jwt.verify(token, jwtSecret) as any; const decoded = jwt.verify(token, jwtSecret) as any;
const authRes = await authUser(decoded.username, decoded.password);
if (!authRes) {
throw createError({ statusCode: 401, statusMessage: 'Username or password is incorrect' });
}
// 生成新的 Token // 生成新的 Token
const newToken = jwt.sign({ const newToken = jwt.sign({
username: decoded.username, username: decoded.username,
+1 -4
View File
@@ -20,10 +20,7 @@ export default defineEventHandler(async (event) => {
// throw createError({ statusCode: 400, statusMessage: 'Username already exists' }); // throw createError({ statusCode: 400, statusMessage: 'Username already exists' });
// } // }
// 哈希密码,暂未实现,未来实现 const hashedPassword = bcrypt.hashSync(password, 10);
// const salt = getKey().substring(0, 10);
// const hashedPassword = bcrypt.hashSync(password, salt);
const hashedPassword = password
// 插入新用户 // 插入新用户
const createTime = Date.now(); const createTime = Date.now();
+5 -11
View File
@@ -1,4 +1,4 @@
// import bcrypt from 'bcryptjs'; import bcrypt from 'bcryptjs';
import BetterSqlite3 from 'better-sqlite3'; import BetterSqlite3 from 'better-sqlite3';
// import { defineEventHandler, createError, readBody } from 'h3'; // import { defineEventHandler, createError, readBody } from 'h3';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
@@ -27,18 +27,12 @@ export default defineEventHandler(async (event) => {
} }
// 验证旧密码是否正确 // 验证旧密码是否正确
// const passwordMatch = bcrypt.compareSync(oldPassword, user.password); const authRes = await authUser(username, oldPassword);
const passwordMatch = oldPassword === user.password; if (!authRes) {
if (!passwordMatch) {
userDB.close(); userDB.close();
throw createError({ statusCode: 401, statusMessage: 'Invalid old password' }); throw createError({ statusCode: 401, statusMessage: 'Old password is incorrect' });
} }
const hashedNewPassword = bcrypt.hashSync(newPassword, 10);
// 哈希新密码
// const salt = bcrypt.genSaltSync(10);
// const hashedNewPassword = bcrypt.hashSync(newPassword, salt);
const hashedNewPassword = newPassword;
// 更新密码 // 更新密码
const stmt = userDB.prepare('UPDATE user SET password =? WHERE username =?'); const stmt = userDB.prepare('UPDATE user SET password =? WHERE username =?');
+4 -2
View File
@@ -1,5 +1,4 @@
import serverConfig from "../server.config" import serverConfig from "../server.config"
// import { verify } from 'jsonwebtoken'
import jwt from 'jsonwebtoken' import jwt from 'jsonwebtoken'
import getKey from "../utils/getKey" import getKey from "../utils/getKey"
@@ -17,10 +16,13 @@ export default defineEventHandler(async (event) => {
const token = authHeader.split('Bearer ')[1].trim() const token = authHeader.split('Bearer ')[1].trim()
try { try {
const decoded = jwt.verify(token, key) as { userId: number, password: string, username: string, exp: number } const decoded = jwt.verify(token, key) as { userId: number, password: string, username: string, exp: number }
const authRes = await authUser(decoded.username, decoded.password)
if (!authRes) {
throw createError({ statusCode: 401, statusMessage: 'Token invalid or expired', data: { err: 'auth failed', token } })
}
if (decoded.exp > Date.now()) { if (decoded.exp > Date.now()) {
throw createError({ statusCode: 401, statusMessage: 'Token invalid or expired', data: { err: 'token expired', token } }) throw createError({ statusCode: 401, statusMessage: 'Token invalid or expired', data: { err: 'token expired', token } })
} }
// console.log(decoded)
// 将用户ID挂载到事件对象,供后续使用 // 将用户ID挂载到事件对象,供后续使用
// event.context.userId = decoded.userId // event.context.userId = decoded.userId
} catch (err) { } catch (err) {
+1
View File
@@ -5,6 +5,7 @@ export default {
'/api/test/testDir', '/api/test/testDir',
'/api/posts/editPost', '/api/posts/editPost',
'/api/posts/uploadPost', '/api/posts/uploadPost',
'/api/posts/deletePost',
'/api/user/updatePassword', '/api/user/updatePassword',
'/api/system/update' '/api/system/update'
]) ])
+16
View File
@@ -0,0 +1,16 @@
import bcrypt from 'bcryptjs';
import BetterSqlite3 from 'better-sqlite3';
export default async function authUser(
username: string,
password: string
) {
const userDB = BetterSqlite3('./userData/db/user.db');
const user: any = userDB.prepare('SELECT * FROM user WHERE username = ?').get(username);
const bPasswd = bcrypt.compareSync(password, user.password) || password === user.password;
if (!user || !bPasswd) {
userDB.close();
return false;
}
return true;
}