代码拉取完成,页面将自动刷新
package caddy_api_module
import (
"fmt"
"gitee.com/qimingxing666/caddy-api-module/caddyApi"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"github.com/gin-gonic/gin"
"log"
"net/http"
"os"
"strings"
)
// xcaddy build --with gitee.com/qimingxing666/caddy-api-module@v0.0.5
// xcaddy build --with github.com/corazawaf/coraza-caddy/v2 --with gitee.com/qimingxing666/caddy-api-module@v0.0.n
func init() {
// 注册插件
caddy.RegisterModule(&CaddyAPIModule{})
// 注册 Caddyfile 指令
httpcaddyfile.RegisterHandlerDirective("caddy_api_module", parseCaddyfile)
}
// CaddyAPIModule 插件获取参数的结构体
type CaddyAPIModule struct {
ApiResponse string `json:"api_response,omitempty"` // 响应的文本
ApiPort string `json:"api_port,omitempty"` // 内部监听的端口号
ApiUrl32 string `json:"api_url32,omitempty"` // 校验的请求头信息
AllowedIPs []string `json:"allowed_ips,omitempty"` // 允许访问的 IP 列表
}
// CaddyModule 返回模块信息(编译完成/运行时 先调用的)完成之后再调用
func (api *CaddyAPIModule) CaddyModule() caddy.ModuleInfo {
fmt.Println("CaddyAPI模块编入成功!!!")
return caddy.ModuleInfo{
ID: "http.handlers.caddy_api_module",
New: func() caddy.Module { return new(CaddyAPIModule) },
}
}
// Provision 是初始化方法,在这里启动路由(4)
func (api *CaddyAPIModule) Provision(ctx caddy.Context) error {
// fmt.Println("-----4-----Provision")
if api.ApiResponse == "" {
api.ApiResponse = "欢迎使用caddy!"
}
if api.AllowedIPs == nil {
api.AllowedIPs = []string{"127.0.0.1"}
}
if api.ApiPort == "" {
api.ApiPort = ":9999"
}
var authorizeIp []string
fmt.Println("GIN白名单!", authorizeIp)
fmt.Println("32位字符串", api.ApiUrl32)
// 启动Gin服务
go func() {
fmt.Println("GIN监听端口:", api.ApiPort)
// 启动GIN
r := gin.Default()
// 检查校验
r.Use(ip32(api.ApiUrl32))
// 注册路由
caddyApi.CaddyAPI(r, api.ApiUrl32)
// 启动监听
r.Run(api.ApiPort)
}()
// 读取日志并发送(找到方法直接将日志发生到指定服务器了)
// go sendLog.SendFileLog(api.AllowedIPs)
return nil
}
// Validate 是校验方法,校验传递的值是否合法(5)
func (api CaddyAPIModule) Validate() error {
// fmt.Println("-----5-----Validate")
//if api.ApiResponse == "" {
// return errors.New("响应文本不能为空")
//}
return nil
}
// ServeHTTP 是处理 HTTP 请求的方法(6)
func (api *CaddyAPIModule) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
//logger := caddy.Log() // 获取 Caddy 的日志记录器
err := next.ServeHTTP(w, r)
if err != nil {
return err
}
// fmt.Println("-----6-----")
w.Write([]byte(api.ApiResponse))
return nil
}
// parseCaddyfile 用于解析 Caddyfile (2)
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
// fmt.Println("-----2-----解析Caddyfile")
hw := new(CaddyAPIModule)
err := hw.UnmarshalCaddyfile(h.Dispenser)
if err != nil {
return nil, err
}
return hw, nil
}
// UnmarshalCaddyfile 从 Caddyfile 中解析配置(3)
func (api *CaddyAPIModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// fmt.Println("-----3-----解析全局配置的")
for d.Next() {
for d.NextBlock(0) {
switch d.Val() {
case "api_response":
if !d.Args(&api.ApiResponse) {
return d.ArgErr()
}
case "api_port":
if !d.Args(&api.ApiPort) { // 将配置值解析到结构体字段中
return d.ArgErr()
}
case "api_url32":
if !d.Args(&api.ApiUrl32) { // 将配置值解析到结构体字段中
return d.ArgErr()
}
case "allowed_ips":
api.AllowedIPs = d.RemainingArgs() // 解析当前块的所有剩余参数(适合处理列表)
default:
return d.Errf("未知的配置项: %s", d.Val())
}
}
}
return nil
}
// 检查是否匹配
func ip32(ipStr string) gin.HandlerFunc {
return func(c *gin.Context) {
// 检查请求路径是否以随机字符串开头
if !strings.HasPrefix(c.Request.URL.Path, "/"+ipStr) {
c.JSON(403, gin.H{"error": "无权限访问"})
c.Abort() // 退出请求
//os.Exit(1)
return
}
// 校验请求IP是否为999:999:999:999
//fmt.Println("客户端ip", c.GetHeader("X-Forwarded-For"))
if c.GetHeader("X-Forwarded-For") != "999:999:999:999" {
c.JSON(403, gin.H{"error": "无权限访问"})
c.Abort() // 中止请求
//os.Exit(1)
return
}
// 如果 IP 在允许列表中,继续执行后续的处理
c.Next()
}
}
// IP 校验中间件
func IPFilter(allowedIPs []string) gin.HandlerFunc {
return func(c *gin.Context) {
// 获取客户端的 IP 地址
clientIP := c.ClientIP()
// 如果 clientIP 是代理服务器的 IP,尝试从 X-Forwarded-For 中获取真实 IP
forwardedIPs := c.Request.Header.Get("X-Forwarded-For")
if forwardedIPs != "" {
// X-Forwarded-For 可能包含多个 IP(client, proxy1, proxy2, ...)
ips := strings.Split(forwardedIPs, ",")
if len(ips) > 0 {
clientIP = strings.TrimSpace(ips[0]) // 取第一个 IP
}
}
//fmt.Println("客户端IP地址:", clientIP)
//log.Println("客户端IP地址:", clientIP)
// 检查 IP 是否在允许的列表中
if !isAllowedIP(clientIP, allowedIPs) {
// 如果 IP 不在允许列表中,拒绝访问
c.JSON(http.StatusForbidden, gin.H{
"code": 403,
"msg": "无权限访问",
"data": nil,
})
c.Abort() // 阻止继续往下执行
return
}
// 如果 IP 在允许列表中,继续执行后续的处理
c.Next()
}
}
// 检查 IP 是否在允许的列表中
func isAllowedIP(ip string, allowedIPs []string) bool {
for _, allowedIP := range allowedIPs {
if ip == allowedIP {
return true
}
}
return false
}
func logs() {
// 创建或打开日志文件
file, err := os.OpenFile("caddyApp.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
if err != nil {
fmt.Println("Error opening log file:", err)
return
}
// 设置 log 包输出到文件
log.SetOutput(file)
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) // 设置日志输出格式
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。