当前位置:   article > 正文

golang实现一个BasicAuth的HTTP server

golang实现一个BasicAuth的HTTP server

之前写的《golang实现一个简单的HTTP server》没有包含认证部分
本例给出了支持BasicAuth的实现,以及如何在一个项目中导入自己定义的package

编写代码

  • 创建项目所在文件夹
admin@hpc-1:~/go$ mkdir auth_http
admin@hpc-1:~/go$ cd auth_http
admin@hpc-1:~/go/auth_http$
  • 1
  • 2
  • 3
  • 项目初始化为一个模块,多出了一个go.mod文件
admin@hpc-1:~/go/auth_http$ go mod init my_auth
go: creating new go.mod: module my_auth
admin@hpc-1:~/go/auth_http$ 

admin@hpc-1:~/go/auth_http$ cat go.mod 
module my_auth

go 1.18
admin@hpc-1:~/go/auth_http$ 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 补齐代码后的目录结构
admin@hpc-1:~/go/auth_http$ tree
.
├── go.mod
├── http_rpc_server.go
└── utils
    └── do_auth.go

1 directory, 3 files
admin@hpc-1:~/go/auth_http$ 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 代码内容
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{}

// 定义一个用于接收请求的方法
func (m *MapPrinter) PrintMap(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        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
    }

    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", "指定监听端口")
    // 解析命令行参数
    flag.Parse()

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

admin@hpc-1:~/go/auth_http$ 
admin@hpc-1:~/go/auth_http$ 
admin@hpc-1:~/go/auth_http$ 
admin@hpc-1:~/go/auth_http$ cat utils/do_auth.go 
package utils

func CheckCredentials(username, password string) bool {
        validUsername := "admin"
        validPassword := "admin"

        return username == validUsername && password == validPassword
}
admin@hpc-1:~/go/auth_http$ 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

一些说明

  • go mode init <package_name>是将代码从GOPATH 模式迁移到模块模式。然后使用模块路径来导入其他模块或包
  • golang的项目必须要有
    • 至少一个go文件以package main开头
    • 有且仅有一个go文件包含func main()作为程序执行的入口
  • utils目录下的所有文件(本例中只有do_auth.go一个文件)都以package utils开头,表明这些文件都属于utils这个自定义包的组成部分
  • 注意,utils中的函数如何要被外部函数调用,必须以大写字母开头,例如本例中的CheckCredentials
  • 当要调用utils中的函数的时候
    • import "my_auth/utils",就是由init时候创建的模块加上"/",再加上自定义的package name
    • 调用utils里面的函数的时候,使用utils.Xxxxx来调用,此时和那个函数具体写在哪个文件中就没有关系了(本例中调用时候就不会出现do_auth这个文件名)

运行

  • 编译出可执行文件
admin@hpc-1:~/go/auth_http$ go build -o http_rpc_server
admin@hpc-1:~/go/auth_http$ 
admin@hpc-1:~/go/auth_http$ file http_rpc_server
http_rpc_server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, Go BuildID=jj_W4SsJdLxNOWHH706-/p8kU3nvIDJ1cRjEIGWFi/752lBQWnErUy3P6gdHgN/2ksEePP3sNj-He57uoCu, not stripped
admin@hpc-1:~/go/auth_http$ 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 运行
admin@hpc-1:~/go/auth_http$ chmod +x http_rpc_server
admin@hpc-1:~/go/auth_http$ 
admin@hpc-1:~/go/auth_http$ ./http_rpc_server -p 8090
Server is listening on port %s... 8090

  • 1
  • 2
  • 3
  • 4
  • 5

验证

不指定auth header

  • 另开终端,用curl发送POST请求,不带username-password
admin@hpc-1:~/go/auth_http$ curl -X POST  -H "Content-Type: application/json" -d '{"key1":"value1", "key2":"value2"}' http://localhost:8090/abc-api
401 Unauthorized
admin@hpc-1:~/go/auth_http$ 
  • 1
  • 2
  • 3

auth header与期望的不匹配

  • 代码中期望用户名和密码为admin/admin,故意不匹配
admin@hpc-1:~/go/auth_http$ curl -X POST -u admin:password -H "Content-Type: application/json" -d '{"key1":"value1", "key2":"value2"}' http://localhost:8090/abc-api
401 Unauthorized
admin@hpc-1:~/go/auth_http$ 
  • 1
  • 2
  • 3

auth header与期望的匹配

  • 匹配期望的用户名密码
admin@hpc-1:~/go/auth_http$ 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:~/go
  • 1
  • 2
  • 3
  • 启动server的终端打印
admin@hpc-1:~/go/auth_http$ ./http_rpc_server -p 8090
Server is listening on port %s... 8090
Received payload:
key1: value1
key2: value2

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/158533
推荐阅读
相关标签
  

闽ICP备14008679号