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
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())
|
|
}
|
|
|