golang通过参数控制HTTP server是否使用基本认证

之前写的《golang实现一个BasicAuth的HTTP server》一定会做基本认证。
本例给出了如何通过启动时候指定的参数来控制是否做基本认证

代码对比和解释

  • 给出与上一篇中源码的diff
admin@hpc-1:~/go/auth_http$ diff -ruN http_rpc_server.go_bak http_rpc_server.go
--- http_rpc_server.go_bak      2024-03-21 16:53:58.899582234 +0800
+++ http_rpc_server.go  2024-03-21 17:51:01.878115766 +0800
@@ -11,7 +11,9 @@
 
 
 // 定义一个用于接收请求的结构体
-type MapPrinter struct{}
+type MapPrinter struct{
+    AuthEnabled bool
+}
 
 // 定义一个用于接收请求的方法
 func (m *MapPrinter) PrintMap(w http.ResponseWriter, r *http.Request) {
@@ -19,23 +21,26 @@
         http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
         return
     }
-    // 检查认证头部信息
-    username, password, ok := r.BasicAuth()
-    if !ok {
-        // 未提供基本身份验证,返回 401 Unauthorized
-        w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
-        w.WriteHeader(http.StatusUnauthorized)
-        fmt.Fprintln(w, "401 Unauthorized")
-        return
-    }
-    
-    // 验证用户名和密码
-    if !utils.CheckCredentials(username, password) {
-        // 用户名和密码不匹配,返回 401 Unauthorized
-        w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
-        w.WriteHeader(http.StatusUnauthorized)
-        fmt.Fprintln(w, "401 Unauthorized")
-        return
+    // 检查是否启用了基本认证
+    if m.AuthEnabled {
+        // 检查认证头部信息
+        username, password, ok := r.BasicAuth()
+        if !ok {
+            // 未提供基本身份验证,返回 401 Unauthorized
+            w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
+            w.WriteHeader(http.StatusUnauthorized)
+            fmt.Fprintln(w, "401 Unauthorized")
+            return
+        }
+        
+        // 验证用户名和密码
+        if !utils.CheckCredentials(username, password) {
+            // 用户名和密码不匹配,返回 401 Unauthorized
+            w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
+            w.WriteHeader(http.StatusUnauthorized)
+            fmt.Fprintln(w, "401 Unauthorized")
+            return
+        }
     }
 
     var payload map[string]interface{}
@@ -57,11 +62,18 @@
 func main() {
     //获取监听端口,默认8080
     port := flag.String("p", "8080", "指定监听端口")
+    //获取是否使能认证,默认不使能
+    authEnabled := flag.Bool("a", false, "Enable basic authentication")
     // 解析命令行参数
     flag.Parse()
 
+    // 创建RPC服务实例
+    rpcService := &MapPrinter{
+        AuthEnabled: *authEnabled, // 根据命令行参数设置是否启用基本认证
+    }
+
     //注册abc-api路由
-    http.HandleFunc("/abc-api", new(MapPrinter).PrintMap)
+    http.HandleFunc("/abc-api", rpcService.PrintMap)
 
     fmt.Println("Server is listening on port %s...", *port)
     log.Fatal(http.ListenAndServe(":" + *port, nil))
admin@hpc-1:~/go/auth_http$ 
  • 解释
    • 定义的结构体MapPrinter增加一个bool属性AuthEnabled ,用来控制是否做基本认证
    • 之前代码中做认证的部分,只有当AuthEnabled为true的时候才执行
    • 通过flag提取-a后面跟着的true或是false用来给AuthEnabled 赋值,默认为false
    • 创建实例rpcService的时候,将flag获取的值赋给AuthEnabled
    • 注册路由的时候,直接关联到实例rpcService
  • 完整源码
admin@hpc-1:~/go/auth_http$ cat http_rpc_server.go
package main

import (
    "fmt"
    "log"
    "flag"
    "net/http"
    "encoding/json"
    "my_auth/utils"
)


// 定义一个用于接收请求的结构体
type MapPrinter struct{
    AuthEnabled bool
}

// 定义一个用于接收请求的方法
func (m *MapPrinter) PrintMap(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }
    // 检查是否启用了基本认证
    if m.AuthEnabled {
        // 检查认证头部信息
        username, password, ok := r.BasicAuth()
        if !ok {
            // 未提供基本身份验证,返回 401 Unauthorized
            w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
            w.WriteHeader(http.StatusUnauthorized)
            fmt.Fprintln(w, "401 Unauthorized")
            return
        }
        
        // 验证用户名和密码
        if !utils.CheckCredentials(username, password) {
            // 用户名和密码不匹配,返回 401 Unauthorized
            w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
            w.WriteHeader(http.StatusUnauthorized)
            fmt.Fprintln(w, "401 Unauthorized")
            return
        }
    }

    var payload map[string]interface{}
    err := json.NewDecoder(r.Body).Decode(&payload)
    if err != nil {
        http.Error(w, "Invalid payload", http.StatusBadRequest)
        return
    }

    fmt.Println("Received payload:")
    for key, value := range payload {
        fmt.Printf("%s: %v\n", key, value)
    }

    w.WriteHeader(http.StatusOK)
    w.Write([]byte("Map printed successfully\n"))
}

func main() {
    //获取监听端口,默认8080
    port := flag.String("p", "8080", "指定监听端口")
    //获取是否使能认证,默认不使能
    authEnabled := flag.Bool("a", false, "Enable basic authentication")
    // 解析命令行参数
    flag.Parse()

    // 创建RPC服务实例
    rpcService := &MapPrinter{
        AuthEnabled: *authEnabled, // 根据命令行参数设置是否启用基本认证
    }

    //注册abc-api路由
    http.HandleFunc("/abc-api", rpcService.PrintMap)

    fmt.Println("Server is listening on port %s...", *port)
    log.Fatal(http.ListenAndServe(":" + *port, nil))
}
admin@hpc-1:~/go/auth_http$ 

验证

不使能认证

  • 运行时候不指定-a,或者 -a=false,注意,不能使用"-a false",否则一直是true!
admin@hpc-1:~/go/auth_http$ ./http_rpc_server -p 8090 -a=false
Server is listening on port %s... 8090
  • 另开终端,无论是不带basic auth header还是随便带什么basic authen header,都可以正常提供服务
admin@hpc-1:~$ curl -X POST  -H "Content-Type: application/json" -d '{"key1":"value1", "key2":"value2"}' http://localhost:8090/abc-api
Map printed successfully
admin@hpc-1:~$ 
admin@hpc-1:~$ curl -X POST -u admin:admin -H "Content-Type: application/json" -d '{"key1":"value1", "key2":"value2"}' http://localhost:8090/abc-api
Map printed successfully
admin@hpc-1:~$ 

使能认证

  • 运行时指定-a=true
admin@hpc-1:~/go/auth_http$ ./http_rpc_server -p 8090 -a=true
Server is listening on port %s... 8090
  • 无论是不带基础认证或者是用户名密码不匹配,都会报错
admin@hpc-1:~$ curl -X POST  -H "Content-Type: application/json" -d '{"key1":"value1", "key2":"value2"}' http://localhost:8090/abc-api
401 Unauthorized
admin@hpc-1:~$ 
admin@hpc-1:~$ curl -X POST -u admin:nimda -H "Content-Type: application/json" -d '{"key1":"value1", "key2":"value2"}' http://localhost:8090/abc-api
401 Unauthorized
admin@hpc-1:~$ 
  • 只有带正确的用户名密码认证的请求才会被正确处理
admin@hpc-1:~$ curl -X POST -u admin:admin -H "Content-Type: application/json" -d '{"key1":"value1", "key2":"value2"}' http://localhost:8090/abc-api
Map printed successfully
admin@hpc-1:~$ 

额外知识点

  • flag的参数,即可以用空格也可以用=连接flag和赋值(-p=8090 和 -p 8090等价)
  • 只有bool类型是例外,只能是用=
本例中,默认指定authEnabled 为false

下面用法表示false
(1)$ ./http_rpc_server -p=8090 -a=false
(2)$ ./http_rpc_server -p=8090 

下面用法表示true
(1)$ ./http_rpc_server -p=8090 -a=true
(2)$ ./http_rpc_server -p=8090 -a
(3) ./http_rpc_server -p=8090 -a <随便什么非空格字符,甚至可以是false>
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值