HTTP BASIC认证

BASIC认证概述

HTTP协议进行通信的过程中,HTTP协议定义了基本认证过程以允许HTTP服务器对WEB浏览器进行用户身份证的方法,当一个客户端向HTTP服务 器进行数据请求时,如果客户端未被认证,则HTTP服务器将通过基本认证过程对客户端的用户名及密码进行验证,以决定用户是否合法。客户端在接收到HTTP服务器的身份认证要求后,会提示用户输入用户名及密码,然后将用户名及密码以BASE64加密,加密后的密文将附加于请求信息中, 如当用户名为:iris,密码为:123456时,客户端将用户名和密码用:合并,并将合并后的字符串用BASE64加密为密文,并于每次请求数据 时,将密文附加于请求头(Request Header)中。HTTP服务器在每次收到请求包后,根据协议取得客户端附加的用户信息(BASE64加密的用户名和密码),解开请求包,对用户名及密码进行验证,如果用 户名及密码正确,则根据客户端请求,返回客户端所需要的数据;否则,返回错误代码或重新要求客户端提供用户名及密码。

BASIC认证的过程

  • 客户端向服务器请求数据,请求的内容可能是一个网页或者是一个其它的MIME类型,此时,假设客户端尚未被验证,则客户端提供如下请求至服务器:
  1. Get /index.html HTTP/1.0
  2. Host:www.studyiris.com
  • 服务器向客户端发送验证请求代码401,服务器返回的数据:
  1. HTTP/1.0 401 Unauthorised
  2. Server: nginx/1.0
  3. WWW-Authenticate: Basic realm="studyiris.com"
  4. Content-Type: text/html
  5. Content-Length: xxx
  • 当符合http1.01.1规范的客户端浏览器收到401返回值时,将自动弹出一个登录窗口,要求用户输入用户名和密码
  • 用户输入用户名和密码后,将用户名及密码以BASE64加密方式加密,并将密文放入前一条请求信息中,则客户端发送的第一条请求信息则变成如下内容:
  1. Get /index.html HTTP/1.0
  2. Host:www.studyiris.com
  3. Authorization: Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxx //加密串
  • 服务器收到上述请求信息后,将Authorization字段后的用户信息取出、解密,将解密后的用户名及密码与用户数据库进行比较验证,如用户名及密码正确,服务器则根据请求,将所请求资源发送给客户端

BASIC认证缺点

HTTP基本认证的目标是提供简单的用户验证功能,其认证过程简单明了,适合于对安全性要求不高的系统或设备中,如大家所用路由器的配置页面的认证,几乎 都采取了这种方式。其缺点是没有灵活可靠的认证策略,如无法提供域(domainrealm)认证功能,另外,BASE64的加密强度非常低。当然,HTTP基本认证系统也可以其他加密技术一起,实现安全性能较高(相对)的认证系统

目录结构

主目录basicauth

  1. —— main.go
  2. —— main_test.go

代码示例

main.go

  1. package main
  2. import (
  3. "time"
  4. "github.com/kataras/iris"
  5. "github.com/kataras/iris/middleware/basicauth"
  6. )
  7. func newApp() *iris.Application {
  8. app := iris.New()
  9. authConfig := basicauth.Config{
  10. Users: map[string]string{"myusername": "mypassword", "mySecondusername": "mySecondpassword"},
  11. Realm: "Authorization Required", // 默认表示域 "Authorization Required"
  12. Expires: time.Duration(30) * time.Minute,
  13. }
  14. authentication := basicauth.New(authConfig)
  15. //作用范围 全局 app.Use(authentication) 或者 (app.UseGlobal 在Run之前)
  16. //作用范围 单个路由 app.Get("/mysecret", authentication, h)
  17. app.Get("/", func(ctx iris.Context) { ctx.Redirect("/admin") })
  18. //作用范围 Party
  19. needAuth := app.Party("/admin", authentication)
  20. {
  21. //http://localhost:8080/admin
  22. needAuth.Get("/", h)
  23. // http://localhost:8080/admin/profile
  24. needAuth.Get("/profile", h)
  25. // http://localhost:8080/admin/settings
  26. needAuth.Get("/settings", h)
  27. }
  28. return app
  29. }
  30. func main() {
  31. app := newApp()
  32. // open http://localhost:8080/admin
  33. app.Run(iris.Addr(":8080"))
  34. }
  35. func h(ctx iris.Context) {
  36. username, password, _ := ctx.Request().BasicAuth()
  37. //第三个参数因为中间件所以不需要判断其值,否则不会执行此处理程序
  38. ctx.Writef("%s %s:%s", ctx.Path(), username, password)
  39. }

文件名称main_test.go

  1. package main
  2. import (
  3. "testing"
  4. "github.com/kataras/iris/httptest"
  5. )
  6. func TestBasicAuth(t *testing.T) {
  7. app := newApp()
  8. e := httptest.New(t, app)
  9. // redirects to /admin without basic auth
  10. e.GET("/").Expect().Status(httptest.StatusUnauthorized)
  11. // without basic auth
  12. e.GET("/admin").Expect().Status(httptest.StatusUnauthorized)
  13. // with valid basic auth
  14. e.GET("/admin").WithBasicAuth("myusername", "mypassword").Expect().
  15. Status(httptest.StatusOK).Body().Equal("/admin myusername:mypassword")
  16. e.GET("/admin/profile").WithBasicAuth("myusername", "mypassword").Expect().
  17. Status(httptest.StatusOK).Body().Equal("/admin/profile myusername:mypassword")
  18. e.GET("/admin/settings").WithBasicAuth("myusername", "mypassword").Expect().
  19. Status(httptest.StatusOK).Body().Equal("/admin/settings myusername:mypassword")
  20. // with invalid basic auth
  21. e.GET("/admin/settings").WithBasicAuth("invalidusername", "invalidpassword").
  22. Expect().Status(httptest.StatusUnauthorized)
  23. }

提示

  • 运行上面的代码,访问http://localhost:8080/admin
  • 未验证时候会弹出一个验证框,让你输入用户名与密码,请认真看弹出框上面的内容
  • 细心的朋友会发现过期时间设置不起作用,因为还需要设置一个expirEnbaletrue