如何在Go中通过HTTP实现RPC服务端与客户端认证?附示例
Go RPC 基于HTTP基础认证的实现示例
服务端实现(带Basic Auth校验)
在原有HTTP RPC服务外层添加认证中间件,拦截请求并校验客户端的基础认证信息:
package main import ( "encoding/base64" "fmt" "net/http" "net/rpc" "strings" ) // RPC服务定义,沿用示例中的算术服务 type Arith int func (t *Arith) Multiply(args *struct{A, B int}, reply *int) error { *reply = args.A * args.B return nil } // BasicAuthMiddleware 基础认证中间件 func BasicAuthMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { authHeader := r.Header.Get("Authorization") if authHeader == "" { w.Header().Set("WWW-Authenticate", `Basic realm="RPC Service"`) http.Error(w, "认证失败", http.StatusUnauthorized) return } // 解析Basic Auth格式的请求头 parts := strings.SplitN(authHeader, " ", 2) if len(parts) != 2 || parts[0] != "Basic" { http.Error(w, "无效的认证格式", http.StatusUnauthorized) return } decoded, err := base64.StdEncoding.DecodeString(parts[1]) if err != nil { http.Error(w, "认证信息解码失败", http.StatusUnauthorized) return } // 校验用户名和密码 credentials := strings.SplitN(string(decoded), ":", 2) if len(credentials) != 2 || credentials[0] != "demo_user" || credentials[1] != "demo_pass" { http.Error(w, "用户名或密码错误", http.StatusUnauthorized) return } // 认证通过,转发请求到RPC处理逻辑 next.ServeHTTP(w, r) }) } func main() { arith := new(Arith) rpc.Register(arith) rpc.HandleHTTP() // 用认证中间件包裹RPC的HTTP处理器 http.Handle("/rpc", BasicAuthMiddleware(http.DefaultServeMux)) fmt.Println("RPC服务启动,监听8080端口") if err := http.ListenAndServe(":8080", nil); err != nil { fmt.Printf("服务启动失败: %v\n", err) } }
客户端实现(携带Basic Auth请求)
客户端在发起RPC请求时,通过HTTP请求头携带基础认证信息,这里用自定义HTTP请求的方式实现:
package main import ( "encoding/base64" "fmt" "net/http" "net/rpc" ) func main() { // 构造Basic Auth认证字符串 username := "demo_user" password := "demo_pass" authStr := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password))) // 创建HTTP请求并添加认证头 req, err := http.NewRequest("POST", "http://localhost:8080/rpc", nil) if err != nil { fmt.Printf("创建请求失败: %v\n", err) return } req.Header.Set("Authorization", "Basic "+authStr) // 发起请求并基于响应创建RPC客户端 httpClient := &http.Client{} resp, err := httpClient.Do(req) if err != nil { fmt.Printf("发起请求失败: %v\n", err) return } defer resp.Body.Close() rpcClient, err := rpc.NewClient(resp.Body) if err != nil { fmt.Printf("创建RPC客户端失败: %v\n", err) return } defer rpcClient.Close() // 调用RPC乘法方法 var reply int args := struct{A, B int}{A: 4, B: 6} err = rpcClient.Call("Arith.Multiply", args, &reply) if err != nil { fmt.Printf("RPC调用失败: %v\n", err) return } fmt.Printf("4 * 6 = %d\n", reply) }
核心说明
- 服务端中间件会优先拦截所有
/rpc路径的请求,完成认证校验后才会放行到RPC处理逻辑,未通过认证的请求会直接返回401状态码。 - 客户端通过在HTTP请求头中添加
Authorization: Basic <base64编码的用户名:密码>字段完成认证,确保请求能通过服务端校验。 - 实际使用时可将硬编码的用户名密码改为从配置文件读取,或接入数据库等存储方式动态校验。
内容的提问来源于stack exchange,提问作者清晨的雾
相关产品推荐
相关产品推荐

