模拟开发授权平台

这次只是实现应用的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)
}

测试截图

相关推荐
Digitally2 小时前
如何轻松地将文件从 iPhone 传输到 PC
ios·iphone
handsome091610 小时前
构建版本没mac上传APP方法
macos
Digitally11 小时前
如何在 Windows 10 PC 上获取 iPhone短信
ios·iphone
忒可君13 小时前
QT5.15 MacOS 打包指南
qt·macos·策略模式
小钱c718 小时前
Mac安装配置InfluxDB,InfluxDB快速入门,Java集成InfluxDB
spring boot·macos·influx
学渣6765618 小时前
macOS烧录stm32程序初步成功
stm32·macos·策略模式
芳草萋萋鹦鹉洲哦18 小时前
【Macos】安装前端环境rust+node环境
前端·macos·rust
他们都不看好你,偏偏你最不争气18 小时前
OC语言学习——Foundation框架回顾及考核补缺
开发语言·学习·ios·objective-c·xcode
侧耳倾听1111 天前
windows和mac安装虚拟机-详细教程
windows·macos
Hi洛一1 天前
Attu下载 Mac版与Win版
macos