You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

73 lines
2.1 KiB

import { logger } from "@/logger"
import jwt from "./jwt"
import { minimatch } from "minimatch"
export const JWT_SECRET = process.env.JWT_SECRET
function matchList(list, path) {
for (const item of list) {
if (typeof item === "string" && minimatch(path, item)) {
return { matched: true, auth: false }
}
if (typeof item === "object" && minimatch(path, item.pattern)) {
return { matched: true, auth: item.auth }
}
}
return { matched: false }
}
function verifyToken(ctx) {
let token = ctx.headers["authorization"]?.replace(/^Bearer\s/, "")
if (!token) {
return { ok: false, status: -1 }
}
try {
ctx.state.user = jwt.verify(token, JWT_SECRET)
return { ok: true }
} catch {
ctx.state.user = undefined
return { ok: false }
}
}
export default function authMiddleware(options = {
whiteList: [],
blackList: []
}) {
return async (ctx, next) => {
if(ctx.session.user) {
ctx.state.user = ctx.session.user
}
// 黑名单优先生效
if (matchList(options.blackList, ctx.path).matched) {
ctx.status = 403
ctx.body = { success: false, error: "禁止访问" }
return
}
// 白名单处理
const white = matchList(options.whiteList, ctx.path)
if (white.matched) {
if (white.auth === false) {
return await next()
}
if (white.auth === "try") {
verifyToken(ctx)
return await next()
}
// true 或其他情况,必须有token
if (!verifyToken(ctx).ok) {
ctx.status = 401
ctx.body = { success: false, error: "未登录或token缺失或无效" }
return
}
return await next()
}
// 非白名单,必须有token
if (!verifyToken(ctx).ok) {
ctx.status = 401
ctx.body = { success: false, error: "未登录或token缺失或无效" }
return
}
await next()
}
}