1
0

basic_auth.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package web
  2. import (
  3. "backup-x/entity"
  4. "bytes"
  5. "encoding/base64"
  6. "log"
  7. "net/http"
  8. "strings"
  9. "time"
  10. )
  11. // ViewFunc func
  12. type ViewFunc func(http.ResponseWriter, *http.Request)
  13. type loginDetect struct {
  14. FailTimes int
  15. }
  16. var ld = &loginDetect{}
  17. // BasicAuth basic auth
  18. func BasicAuth(f ViewFunc) ViewFunc {
  19. return func(w http.ResponseWriter, r *http.Request) {
  20. conf, _ := entity.GetConfigCache()
  21. // 帐号或密码为空。跳过
  22. if conf.Username == "" && conf.Password == "" {
  23. // 执行被装饰的函数
  24. f(w, r)
  25. return
  26. }
  27. // 认证帐号密码
  28. basicAuthPrefix := "Basic "
  29. // 获取 request header
  30. auth := r.Header.Get("Authorization")
  31. // 如果是 http basic auth
  32. if strings.HasPrefix(auth, basicAuthPrefix) {
  33. // 解码认证信息
  34. payload, err := base64.StdEncoding.DecodeString(
  35. auth[len(basicAuthPrefix):],
  36. )
  37. if err == nil {
  38. pair := bytes.SplitN(payload, []byte(":"), 2)
  39. if len(pair) == 2 &&
  40. bytes.Equal(pair[0], []byte(conf.Username)) &&
  41. bytes.Equal(pair[1], []byte(conf.Password)) {
  42. ld.FailTimes = 0
  43. // 执行被装饰的函数
  44. f(w, r)
  45. return
  46. }
  47. }
  48. ld.FailTimes = ld.FailTimes + 1
  49. if ld.FailTimes > 5 {
  50. log.Printf("%s 登陆失败超过5次! 并延时60s响应\n", r.RemoteAddr)
  51. time.Sleep(60 * time.Second)
  52. ld.FailTimes = 0
  53. }
  54. log.Printf("%s 登陆失败!\n", r.RemoteAddr)
  55. }
  56. // 认证失败,提示 401 Unauthorized
  57. // Restricted 可以改成其他的值
  58. w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
  59. // 401 状态码
  60. w.WriteHeader(http.StatusUnauthorized)
  61. log.Printf("%s 请求登陆!\n", r.RemoteAddr)
  62. }
  63. }