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 浏览器交互流程
- 浏览器GET请求/actuator/metrics接口
- 服务器返回401响应,表示该资源需要授权访问(basic auth)
- 浏览器弹出用户名和密码输入框,让用户提供凭证。用户输入信息后,将凭证信息进行相应的编码后,再次发送请求到服务器。
- 服务器收到用户的请求,提取出用户凭证,校验匹配后,返回包含该资源信息的200成功响应。
注意:
- 如用户输入的凭证信息不匹配,将会再次执行第二步操作,返回401响应(未授权)
- 不同的http客户端,对basic auth的支持会有差异。典型的是通过浏览器访问受保护的资源时,会弹出用户名和密码输入框,而非浏览器客户端,比如在APP中,通过http接口调用时,是不会弹出输入框的。
3.2 http协议交互流程
下面我们具体的看一下http协议的交互流程。
-
客户端发起GET请求
GET /actuator/metrics HTTP/1.1...复制代码
-
服务器发现该资源需要授权访问,而客户端并未提供凭证信息,则向客户端返回401响应(HTTP 401 Unauthorized),以及WWW-Authenticate头部字段。
HTTP/1.1 401 UnauthorizedWWW-Authenticate: Basic realm="Authorization Required"Date: Sun, 24 Mar 2019 01:09:45 GMTContent-Length: 0复制代码
WWW-Authenticate头部字段:
WWW-Authenticate: Basic realm="Authorization Required"复制代码
其中,Basic表示使用basic认证算法,realm表示区域,不同的区域可以使用不同的用户名和密码。
服务器也可以带上编码字段,表明服务器期望客户端使用相应的编码去encode用户名和密码。
WWW-Authenticate: Basic realm="Authorization Required", charset="UTF-8"复制代码
-
客户端获取到用户名和密码后,进行Base64编码后,向服务器再次发起请求,请求中通常在header中通过Authorization字段带上认证信息。
GET /actuator/metrics HTTP/1.1Host: localhost:9800Authorization: Basic YWRtaW46cGFzcw==...复制代码
Authorization字段信息包含两部分,第一部分是Basic,后面带上一个空格;第二部分是用户凭证信息的编码。编码过程如下:
- 将用户名和密码通过":"进行组合。这里要注意,用户名中不能包含":"这个字符。
- 将组合后的字符串默认使用US-ASCII编码,当然服务器也可以要求使用UTF-8进行编码。
- 将组合后的字符串再通过Base64算法进行编码。
比如:用户名为admin,密码为pass,则编码时先进行组装得到字符串admin:pass,然后对字符串使用ASCII编码,进行Base64后得到字符串YWRtaW46cGFzcw==
-
服务器收到请求后,提取出Authorization字段,校验匹配后,则返回200成功响应。
HTTP/1.1 200 OKContent-Type: application/json; charset=utf-8Date: Sun, 24 Mar 2019 01:11:00 GMTContent-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 OKContent-Type: application/json; charset=utf-8Content-Length: 30...{"status":"up","statusCode":1}复制代码
如果客户端请求时,带上了认证信息,则返回详细的服务健康信息。
GET /actuator/health HTTP/1.1Authorization: Basic YWRtaW46cGFzcw==...复制代码
HTTP/1.1 200 OKContent-Type: application/json; charset=utf-8Date: Sun, 24 Mar 2019 02:37:13 GMTContent-Length: 224{ "details":{ "disk":{ "status":"up","details":{ "free":912524103680,"threshold":0,"total":1127625711616}},"mem":{ "status":"up","details":{ "free":10098888704,"total":17035321344,"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风格的接口及实际开发过程中比较好的工程实践。
本文为作者原创作品,属于《》专辑中的一篇,转载时请备注作者信息及来源。本文原文地址: