我们先来改一点东西,为中间件加上isJwt
,来对于某些不需要登录的我们就可以防止走jwt
中间件的时候抛出错误,只有需要jwt
的api才会走中间件,未正确解析token,抛出错误
修改helpers/auth.js
js
import jwt from 'jsonwebtoken'
export const auth = {
verifyToken,
createAccessToken,
}
function verifyToken(req, isJwt) {
try {
const token = req.headers.get('authorization')
const decoded = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET)
const id = decoded.id
return id
} catch (error) {
if (isJwt) {
throw error
}
}
}
function createAccessToken(payload) {
return jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET, {
expiresIn: '1d',
})
}
为verifyToken
的catch加上判断是否需要jwt
再抛出错误
修改helpser/api/api-handler.js
js
import { NextResponse } from 'next/server'
import { errorHandler, jwtMiddleware, validateMiddleware, identityMiddleware } from '@/helpers/api'
export function apiHandler(handler, { identity, schema, isJwt } = {}) {
return async (req, ...args) => {
try {
const json = await req.json()
req.json = () => json
} catch {}
try {
await jwtMiddleware(req, isJwt)
await identityMiddleware(req, identity)
await validateMiddleware(req, schema)
const responseBody = await handler(req, ...args)
return NextResponse.json(responseBody || {})
} catch (err) {
console.log('global error handler', err)
return errorHandler(err)
}
}
}
添加isJwt
参数,然后传递给jwtMiddleware
最后修改helpser/api/jwt-middleware.js
js
import { auth } from '@/helpers'
export async function jwtMiddleware(req, isJwt = false) {
if (isPublicPath(req)) {
return
}
const id = auth.verifyToken(req, isJwt)
req.headers.set('userId', id)
}
function isPublicPath(req) {
const publicPaths = ['POST:/api/auth/login', 'POST:/api/auth/logout', 'POST:/api/auth/register']
return publicPaths.includes(`${req.method}:${req.nextUrl.pathname}`)
}
让verifyToken
消费它
然后我们为auth
和user
下面的api都加上apiHandler
的第二个参数:isJwt: true
,如下示例:
category
下面进入本节正题,category
的实现:
category数据库操作
先把helpers/db.js
移动到repo
下面:
shell
mv ./helpers/db.js ./helpers/repo/db.js`
并改动helpers/repo/user-repo.js
的db
引用路径,因为我们后续会删除lib
目录
添加category
的数据库操作函数集,helpers/repo/category-repo.js
js
import db from './db'
import Category from '@/models/Category'
import Product from '@/models/Product'
const getAll = async () => {
await db.connect()
const result = await Category.find()
await db.disconnect()
return result
}
const create = async params => {
const { name } = params
await db.connect()
const category = await Category.findOne({ name })
if (category) throw '该分类名称已存在'
const newCategory = new Category({ name })
await newCategory.save()
await db.disconnect()
}
const _delete = async id => {
await db.connect()
const product = await Product.findOne({ category: id })
if (product) throw '请删除与此相关的所有产品'
const category = await Category.findById(id)
if (!category) throw '分类不存在'
await Category.findByIdAndDelete(id)
await db.disconnect()
}
const update = async (id, { name }) => {
await db.connect()
const category = await Category.findById(id)
if (!category) throw '分类不存在'
await Category.findByIdAndUpdate({ _id: id }, { name })
await db.disconnect()
}
export const categoryRepo = {
getAll,
create,
update,
delete: _delete,
}
修改app/api/category/route.js
,实现获取全部分类和创建分类:
js
import z from 'zod'
import { setJson, apiHandler } from '@/helpers/api'
import { categoryRepo } from '@/helpers'
const getCategory = apiHandler(async req => {
const result = await categoryRepo.getAll()
return setJson({
data: result,
})
})
const createCategory = apiHandler(
async req => {
const { name } = await req.json()
await categoryRepo.create({ name })
return setJson({
message: '创建分类成功',
})
},
{
isJwt: true,
identity: 'admin',
schema: z.object({
name: z.string(),
}),
}
)
export const GET = getCategory
export const POST = createCategory
效果如下:
修改app/api/category/[id]/route.js
,实现针对特定分类的功能:
js
import z from 'zod'
import { setJson, apiHandler } from '@/helpers/api'
import { categoryRepo } from '@/helpers'
const deleteCategory = apiHandler(async (req, { params }) => {
const { id } = params
await categoryRepo.delete(id)
return setJson(
{
message: '删除分类成功',
},
{
isJwt: true,
identity: 'admin',
}
)
})
const updateCategory = apiHandler(
async (req, { params }) => {
const { id } = params
const { name } = await req.json()
await categoryRepo.update(id, { name })
return setJson({
message: '更新成功',
})
},
{
isJwt: true,
identity: 'admin',
schema: z.object({
name: z.string(),
}),
}
)
export const DELETE = deleteCategory
export const PUT = updateCategory
效果如下:
可以看到原有的分类已经被删除了