重新学习web后端开发-007-了解http basic auth

540 阅读6分钟

了解http basic auth

open sesame(芝麻开门) - Ali Baba and the Forty Thieves

1. 需求场景

我们在开发api接口时,有时候需要对某些接口进行授权,允许有权限的用户才能访问。对用户进行权限管理通常可以通过cookie/session,token等机制来实现。这些方式比较适合相对复杂的业务权限处理,而http本身提供了一种相对简单的授权方式,就是http basic auth。上节中,我们提到的metrics相关的接口,是需要进行授权后,才能访问,而监控接口主要被内部的监控系统所使用,本身和具体的业务无关,使用http basic auth机制比较切合。

2. Basic Auth简介

Basic Auth是http协议提供的一个简单的认证机制,当我们访问某个受保护的资源(url)时,http服务器将告知客户端该资源需要授权才能访问,随后客户端提供相应的凭证(用户名/密码),服务端收到凭证进行校验,确认无误后,客户端既可访问受保护的资源,否则,将无权访问。

3. Basic Auth基本流程

3.1 浏览器交互流程

Http Basic Auth基本流程

  1. 浏览器GET请求/actuator/metrics接口
  2. 服务器返回401响应,表示该资源需要授权访问(basic auth)
  3. 浏览器弹出用户名和密码输入框,让用户提供凭证。用户输入信息后,将凭证信息进行相应的编码后,再次发送请求到服务器。
  4. 服务器收到用户的请求,提取出用户凭证,校验匹配后,返回包含该资源信息的200成功响应。

注意:

  • 如用户输入的凭证信息不匹配,将会再次执行第二步操作,返回401响应(未授权)
  • 不同的http客户端,对basic auth的支持会有差异。典型的是通过浏览器访问受保护的资源时,会弹出用户名和密码输入框,而非浏览器客户端,比如在APP中,通过http接口调用时,是不会弹出输入框的。

3.2 http协议交互流程

下面我们具体的看一下http协议的交互流程。

  1. 客户端发起GET请求

    GET /actuator/metrics HTTP/1.1
    ...
    
  2. 服务器发现该资源需要授权访问,而客户端并未提供凭证信息,则向客户端返回401响应(HTTP 401 Unauthorized),以及WWW-Authenticate头部字段。

    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: Basic realm="Authorization Required"
    Date: Sun, 24 Mar 2019 01:09:45 GMT
    Content-Length: 0
    
    

    WWW-Authenticate头部字段:

    WWW-Authenticate: Basic realm="Authorization Required"
    

    其中,Basic表示使用basic认证算法,realm表示区域,不同的区域可以使用不同的用户名和密码。

    服务器也可以带上编码字段,表明服务器期望客户端使用相应的编码去encode用户名和密码。

    WWW-Authenticate: Basic realm="Authorization Required", charset="UTF-8"
    
  3. 客户端获取到用户名和密码后,进行Base64编码后,向服务器再次发起请求,请求中通常在header中通过Authorization字段带上认证信息。

    GET /actuator/metrics HTTP/1.1
    Host: localhost:9800
    Authorization: Basic YWRtaW46cGFzcw==
    ...
    

    Authorization字段信息包含两部分,第一部分是Basic,后面带上一个空格;第二部分是用户凭证信息的编码。编码过程如下:

    1. 将用户名和密码通过":"进行组合。这里要注意,用户名中不能包含":"这个字符。
    2. 将组合后的字符串默认使用US-ASCII编码,当然服务器也可以要求使用UTF-8进行编码。
    3. 将组合后的字符串再通过Base64算法进行编码。

    比如:用户名为admin,密码为pass,则编码时先进行组装得到字符串admin:pass,然后对字符串使用ASCII编码,进行Base64后得到字符串YWRtaW46cGFzcw==

  4. 服务器收到请求后,提取出Authorization字段,校验匹配后,则返回200成功响应。

    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Date: Sun, 24 Mar 2019 01:11:00 GMT
    Content-Length: 55
    
    {"name":["all","mem.sys","mem.heap_objects","gc.last"]}
    

3.3 /health接口使用Basic Auth的特殊情况

/health接口在客户端请求时,如果没有带上basic auth信息,则返回简单的服务健康信息。

GET /actuator/health HTTP/1.1
...
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 30
...

{"status":"up","statusCode":1}

如果客户端请求时,带上了认证信息,则返回详细的服务健康信息。

GET /actuator/health HTTP/1.1
Authorization: Basic YWRtaW46cGFzcw==
...

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sun, 24 Mar 2019 02:37:13 GMT
Content-Length: 224

{"details":{"disk":{"status":"up","details":{"free":912524103680,"threshold":0,"total":1127625711616}},"mem":{"status":"up","details":{"free":10098888704,"total":1
7035321344,"used":6936432640}}},"status":"up","statusCode":1}

这里的实现和基本的basic auth流程将不一样,它不会响应401。而是根据客户端请求的情况进行处理。

func ActuatorGetHealthInfo(c *gin.Context) {
	showDetail := false

	// 判断是否使用basic auth
	authHead := c.GetHeader("Authorization")
	if strings.HasPrefix(authHead, "Basic ") {
		// 获取token
		token := authHead[6:]

		// 验证token
		shouldToken := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", utils.GetAppConfig().Management.Security.Account, utils.GetAppConfig().Management.Security.Password)))

		if token == shouldToken {
             // 凭证信息一致,将显示详细信息
			showDetail = true
		}
	}

	// 调用业务逻辑
	r, _ := healthService.HealthInfo(showDetail)

	// 组装返回数据
	c.JSON(http.StatusOK, r)
}

4. Basic Auth优缺点

4.1 Basic Auth优点

  • 简单 - 认证信息使用标准的http头部字段进行传输,不需要使用cookies/session等,也没有复杂的客户端和服务端协商过程。

4.2 Basic Auth缺点

  • 安全 - 认证信息仅仅使用Base64进行编码,并未使用加密算法,基本上等于明文传输,需要使用https进行加密传输。

5. Basic Auth应用场景

Basic Auth比较适合简单的认证场景,尤其是在内网中使用。通常我们会配合https进行信息加密,来提高安全性。

6. 小结

本节通过实际的接口实例介绍了http basic auth的基本流程,优缺点以及应用场景。下一节,我们将介绍关于Restful接口的相关信息、如何设计Restful风格的接口及实际开发过程中比较好的工程实践。

本文为作者原创作品,属于《重新学习web后端开发》专辑中的一篇,转载时请备注作者信息及来源。本文原文地址:www.donnyzhang.com/2019/03/23/…