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.
 
 
 
 
 
 

196 lines
6.5 KiB

import ResponseTime from "./ResponseTime"
import Send from "./Send"
import { resolve } from "path"
import { fileURLToPath } from "url"
import path from "path"
import ErrorHandler from "./ErrorHandler"
import { AuthMiddleware } from "./Auth"
import bodyParser from "koa-bodyparser"
import Views from "./Views"
import Session from "./Session"
import etag from "@koa/etag"
import conditional from "koa-conditional-get"
import Controller from "./Controller/index.js"
import app from "@/global"
import fs from "fs"
import helmet from "koa-helmet"
import ratelimit from "koa-ratelimit"
import { render } from "./PugHelper/sass.js"
import AuthError from "@/utils/error/AuthError.js"
import CommonError from "@/utils/error/CommonError.js"
import { SiteConfigService } from "@/modules/SiteConfig/services/index.js"
import config from "config/index.js"
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const publicPath = resolve(__dirname, "../../public")
/**
* 注册中间件
* @param {app} app
*/
export default async app => {
// 响应时间
app.use(ResponseTime)
// 拦截 Chrome DevTools 探测请求,直接返回 204
app.use((ctx, next) => {
if (ctx.path === "/.well-known/appspecific/com.chrome.devtools.json") {
ctx.status = 204
ctx.body = ""
return
}
return next()
})
// 跨域设置
app.use(async (ctx, next) => {
ctx.set("Access-Control-Allow-Origin", "*")
ctx.set("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS")
ctx.set("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With")
ctx.set("Access-Control-Allow-Credentials", true)
if (ctx.method == "OPTIONS") {
ctx.status = 200
}
return await next()
})
// 安全设置
app.use(
helmet({
contentSecurityPolicy: {
directives: {
"script-src": ["'self'", "'unsafe-inline'"],
},
},
})
)
// 应用限流
const db = new Map()
app.use(
ratelimit({
driver: "memory",
db: db,
duration: 60000,
errorMessage: "Sometimes You Just Have to Slow Down.",
id: ctx => ctx.ip,
headers: {
remaining: "Rate-Limit-Remaining",
reset: "Rate-Limit-Reset",
total: "Rate-Limit-Total",
},
max: 100,
disableHeader: false,
whitelist: ctx => {
// some logic that returns a boolean
},
blacklist: ctx => {
// some logic that returns a boolean
},
})
)
// 提供全局数据
app.use(async (ctx, next) => {
ctx.state.siteConfig = await SiteConfigService.getAll()
ctx.state.$config = config
return await next()
})
// 错误处理,主要处理运行中抛出的错误
app.use(ErrorHandler())
// session设置
app.use(Session(app))
// 视图设置
app.use(
Views(resolve(__dirname, "../views"), {
extension: "pug",
options: {
basedir: resolve(__dirname, "../views"),
filters: {
// 处理scss
scss: function (text, options) {
//- process.env.SASS_PATH = "D:/@code/demo/koa3-demo/src/views/page/index"
const root = path.resolve(__dirname, "../views")
const publicPath = path.resolve(__dirname, "../../public")
const publicScssPath = path.resolve(publicPath, "scss-compiler")
const globalScss = `@import "_scss/global";`
const result = render(globalScss + "\n" + text, {
...options,
includePaths: [...(options.includePaths || []), path.resolve(__dirname, "../views")],
})
return `<style>${result.body}</style>`
},
},
},
})
)
// 权限设置
app.use(
AuthMiddleware({
whiteList: [
// 所有请求放行
{ pattern: "/" },
{ pattern: "/**/*" },
],
blackList: [
// 禁用api请求
// "/api",
// "/api/",
// "/api/**/*",
],
})
)
// 验证用户
// 注入全局变量:ctx.state.user
// app.use(VerifyUserMiddleware())
// 请求体解析
app.use(bodyParser())
app.use(
await Controller({
root: path.resolve(__dirname, "../modules"),
handleBeforeEachRequest: options => {
const { auth = true } = options || {}
return async (ctx, next) => {
if (ctx.session && ctx.session.user) {
ctx.state.user = ctx.session.user
} else {
const authorizationString = ctx.headers && ctx.headers["authorization"]
if (authorizationString) {
const token = authorizationString.replace(/^Bearer\s/, "")
try {
ctx.state.user = jwt.verify(token, process.env.JWT_SECRET)
} catch (_) {
// 无效token忽略
}
}
}
if (auth === false && ctx.state.user) {
throw new CommonError("不能登录查看")
}
if (auth === "try") {
return next()
}
if (auth === true && !ctx.state.user) {
throw new AuthError("需要登录才能访问")
}
return await next()
}
},
})
)
// 注册完成之后静态资源设置
app.use(async (ctx, next) => {
if (ctx.body) return await next()
if (ctx.status === 200) return await next()
if (ctx.method.toLowerCase() === "get") {
try {
await Send(ctx, ctx.path, { root: publicPath, maxAge: 0, immutable: false })
} catch (err) {
if (err.status !== 404) throw err
}
}
await next()
})
app.use(conditional())
app.use(etag())
}