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