模拟开发授权平台

这次只是实现应用的curd和公私钥的校验以及第三方的通知dmeo项目,大家可以拓开视野来编写

进入主题

项目链接:桌角的眼镜/develop_auth_platform

直接下拉并运行就行 回调应用代码在test包中

回调应用测试代码

Go 复制代码
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"time"
)

func main() {
	// 设置路由
	http.HandleFunc("/callback", callbackHandler)
	http.HandleFunc("/", homeHandler)

	// 配置服务器
	server := &http.Server{
		Addr:         ":8089",
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	// 启动服务器
	fmt.Printf("🚀 服务已启动,监听端口 8089\n")
	fmt.Printf("👉 测试接口: curl -X POST http://localhost:8089/callback -d '{\"message\":\"test\"}'\n")

	if err := server.ListenAndServe(); err != nil {
		log.Fatalf("❌ 服务器启动失败: %v", err)
	}
}

// 回调接口处理器
func callbackHandler(w http.ResponseWriter, r *http.Request) {
	// 打印请求基本信息
	fmt.Printf("\n=== 收到回调请求 ===\n")
	fmt.Printf("时间: %s\n", time.Now().Format(time.RFC3339))
	fmt.Printf("方法: %s\n", r.Method)
	fmt.Printf("来源IP: %s\n", r.RemoteAddr)
	fmt.Printf("请求头: %v\n", r.Header)

	// 根据Content-Type处理不同格式的请求体
	contentType := r.Header.Get("Content-Type")
	var body interface{}

	switch contentType {
	case "application/json":
		var jsonBody map[string]interface{}
		if err := json.NewDecoder(r.Body).Decode(&jsonBody); err != nil {
			http.Error(w, "无效的JSON数据", http.StatusBadRequest)
			return
		}
		body = jsonBody
	default:
		// 其他类型直接读取原始数据
		data, err := io.ReadAll(r.Body)
		if err != nil {
			http.Error(w, "读取请求体失败", http.StatusBadRequest)
			return
		}
		body = string(data)
	}

	// 打印请求体
	fmt.Printf("请求体: %+v\n", body)
	fmt.Printf("===================\n")

	// 返回成功响应
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"status":  "success",
		"message": "回调已接收",
		"data":    body,
	})
}

// 首页处理器
func homeHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return
	}
	w.Header().Set("Content-Type", "text/plain")
	fmt.Fprintf(w, "回调服务运行中\n请访问 /callback 接口")
}

项目的简易结构

核心部分

Application的curd

/api/v1/下的application.go

Go 复制代码
package v1

import (
	"github.com/gin-gonic/gin"
	"github.com/spectacleCase/develop_auth_platform/global"
	"github.com/spectacleCase/develop_auth_platform/models"
	request "github.com/spectacleCase/develop_auth_platform/models/request"
)

type Application struct{}

func (Application) Create() gin.HandlerFunc {
	return func(c *gin.Context) {
		var NewApp request.Create
		if err := c.ShouldBind(&NewApp); err != nil {
			models.FailWithMessage("参数有误", c)
			return
		}
		id, err := models.GenerateID()
		if err != nil {
			models.FailWithMessage(err.Error(), c)
			return
		}
		// 得到公私钥
		prKey, puKey, err := models.GetDefaultKeyPair()
		if err != nil {
			models.FailWithMessage(err.Error(), c)
			return
		}
		global.ApplicationList = append(global.ApplicationList, &models.Application{
			Id:          id,
			Name:        NewApp.Name,
			CallbackUrl: NewApp.CallbackUrl,
			PrKey:       prKey,
			PuKey:       puKey,
		})
		models.Ok(c)
		return
	}
}

func (Application) Get() gin.HandlerFunc {
	return func(c *gin.Context) {
		models.OkWithData(global.ApplicationList, c)
		return
	}
}

func (Application) Update() gin.HandlerFunc {
	return func(c *gin.Context) {
		var updateApp request.Update
		if err := c.ShouldBind(&updateApp); err != nil {
			models.FailWithMessage("参数有误", c)
			return
		}
		for index, app := range global.ApplicationList {
			if app == nil {
				continue // 跳过 nil 指针
			}
			if app.Id == updateApp.Id {
				app.Name = updateApp.Name
				app.CallbackUrl = updateApp.CallbackUrl
				global.ApplicationList[index] = app
			}
			models.Ok(c)
			return
		}

		models.FailWithMessage("错误的参数", c)
		return
	}
}

func (Application) Delete() gin.HandlerFunc {
	return func(c *gin.Context) {
		var delApp request.Delete
		if err := c.ShouldBind(&delApp); err != nil {
			models.FailWithMessage("参数有误", c)
			return
		}

		for index, app := range global.ApplicationList {
			if app == nil {
				continue // 跳过 nil 指针
			}
			if app.Id == delApp.Id {
				global.ApplicationList[index] = nil
			}
			models.Ok(c)
			return
		}
		models.FailWithMessage("错误的参数", c)
		return
	}
}

/models下的application.go

Go 复制代码
package models

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"fmt"
)

type Application struct {
	Id          string `json:"id"`
	Name        string `json:"name"`
	PrKey       string `json:"-"`     // 私钥(JSON 序列化时忽略)
	PuKey       string `json:"puKey"` // 公钥
	SerPuKey    string `json:"serPuKey"`
	CallbackUrl string `json:"callbackUrl"` // 回调地址
}

// GenerateID 生成唯一应用ID (UUID简化版)
func GenerateID() (string, error) {
	const length = 16 // 16字节 = 128位
	b := make([]byte, length)
	if _, err := rand.Read(b); err != nil {
		return "", fmt.Errorf("生成ID失败: %v", err)
	}
	return base64.URLEncoding.EncodeToString(b), nil
}

// GenerateKeyPair 生成RSA公私钥对
func GenerateKeyPair(bits int) (prKey, puKey string, err error) {
	privateKey, err := rsa.GenerateKey(rand.Reader, bits)
	if err != nil {
		return "", "", fmt.Errorf("密钥生成失败: %v", err)
	}

	// 编码私钥
	privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
	privateKeyPEM := pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: privateKeyBytes,
	})

	// 编码公钥
	publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
	if err != nil {
		return "", "", fmt.Errorf("公钥编码失败: %v", err)
	}
	publicKeyPEM := pem.EncodeToMemory(&pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: publicKeyBytes,
	})

	return string(privateKeyPEM), string(publicKeyPEM), nil
}

// GetDefaultKeyPair 获取默认强度的密钥对 (2048位)
func GetDefaultKeyPair() (string, string, error) {
	return GenerateKeyPair(2048)
}

// VerifyKeyPair 验证公私钥是否匹配
func VerifyKeyPair(prKey, puKey string) bool {
	block, _ := pem.Decode([]byte(prKey))
	if block == nil {
		return false
	}
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return false
	}

	pubBlock, _ := pem.Decode([]byte(puKey))
	if pubBlock == nil {
		return false
	}
	pubKey, err := x509.ParsePKIXPublicKey(pubBlock.Bytes)
	if err != nil {
		return false
	}

	rsaPubKey, ok := pubKey.(*rsa.PublicKey)
	if !ok {
		return false
	}

	return privateKey.PublicKey.Equal(rsaPubKey)
}

测试截图

相关推荐
Ya-Jun4 小时前
性能优化实践:启动优化方案
android·flutter·ios·性能优化
[奋斗不止]12 小时前
MacOS 安装 cocoapods
macos·cocoapods·mac cocoapods·macos cocoapods
程序务虚论1 天前
抓取工具Charles配置教程(mac电脑+ios手机)
macos·ios·https·charles
帅次1 天前
Flutter BottomNavigationBar 详解
android·flutter·ios·小程序·iphone·reactnative
明似水1 天前
解决 Flutter 在 iOS 真机上构建失败的问题
flutter·ios
WMSmile1 天前
macOS 安装了Docker Desktop版终端docker 命令没办法使用
macos·docker·容器
爱幻想-hjyp1 天前
Mac M1安装 Docker Desktop 后启动没反应
macos·docker·eureka
一只帆記1 天前
M1 Mac pip3 install错误记录
python·macos·pip
前后端杂货铺1 天前
uniapp利用生命周期函数实现后台常驻示例
android·前端·ios·微信小程序·uni-app