进阶 www.iris-go.com 2026-10-20 02:39:14 · 19 阅读
第64章 HTTP Basic Authentication 基本认证中间件
HTTP Basic Authentication
HTTP Basic Authentication(HTTP 基本认证)是保护 Web 资源访问控制最简单的方式,因为它不需要 Cookie、会话标识符或登录页面,而是直接利用 HTTP 报头中的标准字段实现认证。
Basic Authentication 机制不对传输的凭据提供机密性保护。它们只是在进行传输时通过 Base64 编码,既未加密也未经过哈希处理。因此,基本认证通常与 HTTPS 结合使用,以提供机密性保障。
由于 Basic Authentication 字段必须随每个 HTTP 请求的报头发送,Web 浏览器需要在一个合理的时间段内缓存凭据,避免频繁向用户索要用户名和密码。不同浏览器的缓存策略各不相同。
HTTP 协议未提供让 Web 服务器指示客户端执行用户“登出”的方法。不过,Iris 框架的 Basic Authentication 中间件内置了 expiration(过期时间)字段,可用于强制重新要求用户输入凭据;同时提供 Context.Logout 方法,可强制使当前用户会话立即失效。
使用
Basic Authentication 中间件已包含在 Iris 框架中,无需单独安装。
1. 导入中间件
go
import "github.com/kataras/iris/v12/middleware/basicauth"
2. 通过 Options 结构体配置中间件:
go
opts := basicauth.Options{
Allow: basicauth.AllowUsers(map[string]string{
"username": "password",
}),
Realm: "Authorization Required",
ErrorHandler: basicauth.DefaultErrorHandler,
// [...more options]
}
3. 初始化中间件:
go
auth := basicauth.New(opts)
3.1 上述步骤与调用 Default 函数等效:
go
auth := basicauth.Default(map[string]string{
"username": "password",
})
3.2 使用自定义的 Users 切片:
go
// 该结构体值必须包含 Username 和 Passwords 字段
// 或 GetUsername() string 和 GetPassword() string 方法。
type User struct {
Username string
Password string
}
// [...]
auth := basicauth.Default([]User{...})
3.3 可选地从文件加载用户,密码将使用 golang.org/x/crypto/bcrypt 包进行加密:
go
auth := basicauth.Load("users.yml", basicauth.BCRYPT)
### 3.3.1 使用 Options 实现同样功能(推荐)
```go
opts := basicauth.Options{
Allow: basicauth.AllowUsersFile("users.yml", basicauth.BCRYPT),
Realm: basicauth.DefaultRealm,
// [...更多选项]
}
auth := basicauth.New(opts)
```
其中,`users.yml` 文件内容示例如下:
```yaml
- username: kataras
password: $2a$10$Irg8k8HWkDlvL0YDBKLCYee6j6zzIFTplJcvZYKA.B8/clHPZn2Ey
# kataras_pass 的加密值
role: admin
- username: makis
password: $2a$10$3GXzp3J5GhHThGisbpvpZuftbmzPivDMo94XPnkTnDe7254x7sJ3O
# makis_pass 的加密值
role: member
```
### 4. 注册中间件
```go
// 注册到所有匹配的 Party 及其子路由
app.Use(auth)
// 或者,注册到所有 HTTP 错误路由
app.UseError(auth)
// 或者,注册到特定 Party 的路径前缀下,
// 包含该路径前缀下的所有 HTTP 错误
app.UseRouter(auth)
// 或者,在特定 Route 的主处理程序之前注册
app.Post("/protected", auth, routeHandler)
```
### 5. 获取用户名和密码
```go
func routeHandler(ctx iris.Context) {
username, password, _ := ctx.Request().BasicAuth()
// [...]
}
```
### 5.1 获取 User 值(当在 Options.AllowUsers 中注册了自定义用户结构体切片时非常有用)
```go
func routeHandler(ctx iris.Context) {
user := ctx.User().(*iris.SimpleUser)
// user.Username
// user.Password
}
```
### 选项
以下是 `basicauth.Options` 结构的完整列表:
Realm 指令,详情请参阅 [http://tools.ietf.org/html/rfc2617#section-1.2](http://tools.ietf.org/html/rfc2617#section-1.2)。例如 `"Authorization Required"`。
```go
Realm string
```
在代理情况下,挑战状态码为 407(Proxy Authentication Required),`Proxy-Authenticate` 响应头包含至少一个适用于该代理的挑战,而 `Proxy-Authorization` 请求头用于向代理服务器提供凭据。
Proxy 应使用户能够访问代理服务器背后的资源。它向代理服务器验证请求,从而允许其进一步传输该请求。
```go
Proxy bool
```
如果设置为 `true`,则任何非 HTTPS 请求都将立即被丢弃,并返回 505 状态码(StatusHTTPVersionNotSupported)响应。默认为 `false`。
```go
HTTPSOnly bool
```
Options 类型中只有 Allow 是必填字段。它可以自定义用来校验用户名和密码组合,并返回一个用户对象,比如从数据库中获取。内置提供了两个可选值:AllowUsers 和 AllowUsersFile,二者都是解析一份静态用户列表,与用户输入进行比对(另可配合 BCRYPT 函数使用)。
用法:
```go
Allow: AllowUsers(iris.Map{"username": "...", "password": "...", "other_field": ...}, [BCRYPT])
// 或者
Allow: AllowUsersFile("users.yml", [BCRYPT])
```
也可以传入自定义的 AuthFunc:
```go
// 应返回用户值,并报告用户名和密码是否匹配一个已验证的用户。
func(ctx iris.Context, username, password string) (interface{}, bool)
```
MaxAge 用于设置内存中凭证映射的过期时长。默认情况下,旧条目会在用户访问页面时被移除。若希望自动清理旧条目,请参考 GC 选项。
用法:
```go
MaxAge: 30 * time.Minute
```
```go
MaxAge time.Duration
```
MaxTries:如果大于零,当登录失败次数达到 MaxTries 后,服务器会返回 403 禁止访问状态码(见 MaxTriesCookie)。注意,客户端可以修改 cookie 及其值,因此不要基于该字段实现任何自定义的业务逻辑。默认情况下,服务器在凭证无效时每次都会重新要求输入凭证。
```go
MaxTries int
```
MaxTriesCookie 是中间件用来在客户端存储失败次数的 cookie 名称。该 cookie 的有效期与配置的 MaxAge 相同,或为一小时,因此被禁止的客户端在过期后可以重新请求认证。
你可以在 Allow 字段上设置自定义逻辑,因为你可以访问当前的请求实例。
默认值为 "basicmaxtries"。MaxTries 必须设置为大于零。
```go
MaxTriesCookie string
```
MaxTriesSession:如果不为空,则会使用该 session 键来存储当前的登录失败次数。如果没有注册 session 管理器,应用会记录一条错误日志。注意,该字段的优先级高于 MaxTriesCookie。
```go
MaxTriesSession string
```
ErrorHandler 用于处理请求凭证校验失败的情况,例如客户端使用空凭证、无效凭证或过期凭证访问受保护资源时,或者 Allow 返回 false 且 MaxTries 次数已用完时。
默认为 basicauth.DefaultErrorHandler,如无需要请勿修改。
```go
ErrorHandler ErrorHandler
```
其中 ErrorHandler 的类型为:
gofunc(ctx iris.Context, err error)
err 可以是以下类型之一:
gobasicauth.ErrHTTPVersion
basicauth.ErrCredentialsForbidden
basicauth.ErrCredentialsMissing
basicauth.ErrCredentialsInvalid
basicauth.ErrCredentialsExpired
一个典型的用法示例是 DefaultErrorHandler。
GC(垃圾回收)会在每经过 x 时长的间隔后自动清除旧条目。这里的“旧条目”指的是已过期的凭据,因此应提前设置 MaxAge 选项;若未设置,则每次执行 GC 时都会删除所有条目。标准 context 可用于内部定时器的取消,允许为 nil。
用法:
goGC: basicauth.GC{Every: 2 * time.Hour}
goGC GC
GC 类型定义如下:
GC 持有上下文以及清除已存储过期凭据的 tick 时长。参见 Options.GC 字段。
gotype GC struct {
Context context.Context
Every time.Duration
}
测试
下面学习如何使用 Iris 的 httptest 包及其 WithBasicAuth 方法来测试基本认证等操作。
- 导入
httptest子包:
goimport "github.com/kataras/iris/v12/httptest"
- 在测试函数中初始化 tester 对象,需要提供
testing.T和iris.Application实例:
goe := httptest.New(t, app)
- 创建测试用例,并使用其
WithBasicAuth方法生成带有基本认证凭据的请求:
goe.POST("/protected").WithBasicAuth("user", "pass").
Expect().Status(httptest.StatusOK)
完整代码示例位于:_examples/auth/basicauth/basic/main_test.go
就这么简单!