HTTP 鉴权方法详解:Basic vs Bearer 及其他常见认证方式
写接口时经常看到请求头里有 Authorization:Basic xxx 或者 Authorization:Bearer yyy,这俩到底有啥区别?
其实它们是 HTTP 协议定义的两种不同鉴权方式,背后的原理和使用场景完全不同。
Authorization 请求头的作用
HTTP 协议通过 Authorization 请求头来传递身份凭证。格式统一为:
Authorization:<type> <credentials>- type:鉴权类型,比如
Basic、Bearer、Digest等 - credentials:具体的凭证内容,不同类型格式不同
服务端收到请求后,根据 type 决定用什么方式验证 credentials,验证通过就返回数据,失败就返回 401 或 403。
Basic 认证:用户名密码的 Base64 编码
原理
Basic 认证是最简单的鉴权方式,直接把 用户名:密码 拼接后 Base64 编码,放到请求头里。
格式:
Authorization:Basic base64(username:password)比如用户名 admin,密码 123456:
package main
import (
"encoding/base64"
"fmt"
"net/http"
)
func basicAuth(username, password string) string {
auth := username + ":" + password
return base64.StdEncoding.EncodeToString([]byte(auth))
}
func main() {
username := "admin"
password := "123456"
// 生成 Basic 认证凭证
credentials := basicAuth(username, password)
fmt.Println("Authorization:Basic", credentials)
// 输出:Authorization:Basic YWRtaW46MTIzNDU2
// 发送请求
req, _ := http.NewRequest("GET", "https://api.example.com/data", nil)
req.Header.Set("Authorization", "Basic "+credentials)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
fmt.Println("状态码:", resp.StatusCode)
}服务端验证
服务端收到请求后,解码 Base64,拆分用户名和密码,然后去数据库对比:
func parseBasicAuth(authHeader string) (username, password string, ok bool) {
// Authorization:Basic YWRtaW46MTIzNDU2
const prefix = "Basic "
if !strings.HasPrefix(authHeader, prefix) {
return "", "", false
}
// 提取 Base64 部分
encoded := authHeader[len(prefix):]
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return "", "", false
}
// 拆分用户名和密码
credentials := string(decoded)
parts := strings.SplitN(credentials, ":", 2)
if len(parts) != 2 {
return "", "", false
}
return parts[0], parts[1], true
}
func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
username, password, ok := parseBasicAuth(authHeader)
if !ok {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// 验证用户名密码(这里简化处理,实际要查数据库)
if username != "admin" || password != "123456" {
http.Error(w, "Invalid credentials", http.StatusUnauthorized)
return
}
next(w, r)
}
}优缺点
优点:
- 实现简单,浏览器原生支持
- 无需管理 Token 或 Session
缺点:
- 不安全:Base64 只是编码,不是加密,抓包就能看到明文密码
- 每次都传密码:每个请求都带用户名密码,泄露风险大
- 无法撤销:想让某个凭证失效,只能改密码
适用场景:内网工具、开发环境、或者配合 HTTPS 使用。生产环境不推荐单独用 Basic。
Bearer 认证:令牌(Token)方式
原理
Bearer 认证不传用户名密码,而是传一个 Token(令牌)。用户先登录拿到 Token,后续请求都带这个 Token。
格式:
Authorization:Bearer <token>Token 通常是 JWT(JSON Web Token)或者服务端生成的随机字符串。
JWT Token 示例
JWT 是最常用的 Bearer Token 格式,由三部分组成:Header.Payload.Signature。
生成 JWT:
import (
"github.com/golang-jwt/jwt/v5"
"time"
)
var secretKey = []byte("your-secret-key")
// 生成 JWT Token
func generateJWT(userID string) (string, error) {
claims := jwt.MapClaims{
"user_id":userID,
"exp": time.Now().Add(time.Hour * 24).Unix(), // 24 小时过期
"iat": time.Now().Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(secretKey)
}
// 验证 JWT Token
func validateJWT(tokenString string) (*jwt.MapClaims, error) {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return secretKey, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return &claims, nil
}
return nil, fmt.Errorf("invalid token")
}客户端使用:
func requestWithBearer(token string) {
req, _ := http.NewRequest("GET", "https://api.example.com/data", nil)
req.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
fmt.Println("状态码:", resp.StatusCode)
}
func main() {
// 假设已经登录拿到 Token
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
requestWithBearer(token)
}服务端验证:
func bearerAuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
// 检查 Bearer 前缀
const prefix = "Bearer "
if !strings.HasPrefix(authHeader, prefix) {
http.Error(w, "Missing or invalid token", http.StatusUnauthorized)
return
}
// 提取 Token
tokenString := authHeader[len(prefix):]
// 验证 JWT
claims, err := validateJWT(tokenString)
if err != nil {
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
// 可以把用户信息存到上下文
userID := (*claims)["user_id"].(string)
fmt.Println("认证成功,用户 ID:", userID)
next(w, r)
}
}优缺点
优点:
- 更安全:Token 不包含密码,泄露后可以撤销
- 支持过期:Token 可以设置有效期,自动失效
- 无状态:服务端不需要存储 Session,适合分布式系统
- 权限控制:Token 可以携带权限信息(JWT Payload)
缺点:
- 实现稍复杂,需要 Token 管理机制
- JWT 一旦签发无法主动撤销(除非加黑名单)
适用场景:现代 Web API、移动应用、微服务架构。
Basic vs Bearer 核心区别
| 维度 | Basic | Bearer |
|---|---|---|
| 凭证内容 | 用户名:密码(Base64) | Token(通常是 JWT) |
| 安全性 | 低(Base64 可逆) | 高(Token 签名验证) |
| 密码传输 | 每次都传 | 仅登录时传,后续用 Token |
| 撤销能力 | 无法撤销单个凭证 | 可以撤销单个 Token |
| 过期机制 | 无 | 支持过期时间 |
| 适用场景 | 内网工具、简单场景 | 生产环境、API 服务 |
其他常见鉴权方法
1. Digest 认证
Digest 是 Basic 的改进版,不直接传密码,而是传密码的哈希值。
格式:
Authorization:Digest username="admin", realm="api", nonce="...", uri="/data", response="..."流程:
- 客户端请求资源
- 服务端返回 401 + nonce(随机数)
- 客户端用密码 + nonce 计算 MD5,发送 response
- 服务端用相同方法验证
优点:比 Basic 安全,密码不明文传输
缺点:实现复杂,MD5 已不够安全,现代 API 很少用
2. API Key
API Key 是一个固定的密钥字符串,通常放在请求头或 URL 参数里。
格式:
Authorization:ApiKey your-api-key-here或者:
X-API-Key:your-api-key-here优点:简单直接,适合服务间调用
缺点:没有过期机制,泄露后只能重新生成
使用场景:第三方服务调用(如阿里云、腾讯云 API)。
3. OAuth 2.0
OAuth 不是单一鉴权方法,而是一套授权框架。Bearer Token 其实就是 OAuth 2.0 的一部分。
流程:
- 用户授权第三方应用访问资源
- 第三方拿到 Access Token
- 用 Token 请求资源
典型场景:微信登录、GitHub 授权、Google 登录。
4. Hawk / AWS Signature
用请求的内容(URL、参数、时间戳等)生成签名,防止请求被篡改。
格式:
Authorization:Hawk id="user", ts="1353832234", nonce="...", mac="..."AWS 的 API 就是这种方式,每个请求都要用 AccessKey 签名。
优点:防重放攻击,防篡改
缺点:实现复杂,客户端需要精确计算签名
5. Mutual TLS (mTLS)
不用 Authorization 头,而是通过 TLS 双向认证。客户端和服务端都有证书,握手时互相验证。
优点:最安全,不依赖应用层
缺点:证书管理成本高,适合高安全场景(金融、政务)
如何选择鉴权方法
| 场景 | 推荐方法 | 原因 |
|---|---|---|
| 内网工具、快速原型 | Basic | 简单够用 |
| 现代 Web API | Bearer (JWT) | 安全、灵活、无状态 |
| 第三方服务调用 | API Key | 简单直接 |
| 开放平台授权 | OAuth 2.0 | 标准协议,用户信任度高 |
| 高安全金融场景 | mTLS + Bearer | 双重保障 |
常见问题
Basic 和 Bearer 可以同时用吗?
不能。一个请求的 Authorization 头只能有一个值,要么 Basic 要么 Bearer。但可以先用 Basic 登录,拿到 Bearer Token 后切换。
JWT Token 被盗了怎么办?
JWT 一旦签发无法主动撤销,只能等过期。缓解措施:
- 设置短过期时间(如 1 小时)
- 配合 Refresh Token(长期有效,用来换新 Token)
- 维护黑名单(但这样就不是无状态了)
为什么不直接用 Cookie 而要用 Authorization 头?
Cookie 是浏览器自动带的,有 CSRF 风险。Authorization 头需要手动设置,更适合 API 调用,也方便跨域。
HTTPS 下用 Basic 安全吗?
HTTPS 下 Basic 相对安全(传输过程加密),但还是不如 Bearer。
因为服务端日志可能记录 Authorization 头,密码还是可能泄露。
移动 App 该用哪种?
Bearer (JWT)。
移动端用 Basic 风险大(密码存在本地不安全),用 JWT 可以设置过期,被盗后损失可控。
总结
Basic 和 Bearer 本质区别在于:Basic 传的是用户名密码,Bearer 传的是令牌。
Basic 简单但不安全,Bearer 安全但稍复杂。
选择建议:
- 内网快速开发 → Basic + HTTPS
- 生产环境 API → Bearer (JWT)
- 第三方集成 → API Key 或 OAuth
怎么说呢,鉴权这事儿没有银弹,根据场景选最合适的。
如果你的接口对外开放,强烈推荐 Bearer + JWT。
如果只是内部工具,Basic 配合 HTTPS 也够用。
如果大家对 HTTP 鉴权还有疑问,或者在实际项目中遇到过其他问题,欢迎在评论区交流~~~
版权声明
未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!
本文原文链接: https://fiveyoboy.com/articles/http-authentication-methods/
备用原文链接: https://blog.fiveyoboy.com/articles/http-authentication-methods/