目录

HTTP 鉴权方法详解:Basic vs Bearer 及其他常见认证方式

写接口时经常看到请求头里有 Authorization:Basic xxx 或者 Authorization:Bearer yyy,这俩到底有啥区别?

其实它们是 HTTP 协议定义的两种不同鉴权方式,背后的原理和使用场景完全不同。

Authorization 请求头的作用

HTTP 协议通过 Authorization 请求头来传递身份凭证。格式统一为:

Authorization:<type> <credentials>
  • type:鉴权类型,比如 BasicBearerDigest
  • credentials:具体的凭证内容,不同类型格式不同

服务端收到请求后,根据 type 决定用什么方式验证 credentials,验证通过就返回数据,失败就返回 401 或 403。

/img/http-authentication-methods/0101.png
BasicvsBearer认证对比

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、移动应用、微服务架构。

/img/http-authentication-methods/0103.png
JWTToken结构详解

Basic vs Bearer 核心区别

维度 Basic Bearer
凭证内容 用户名:密码(Base64) Token(通常是 JWT)
安全性 低(Base64 可逆) 高(Token 签名验证)
密码传输 每次都传 仅登录时传,后续用 Token
撤销能力 无法撤销单个凭证 可以撤销单个 Token
过期机制 支持过期时间
适用场景 内网工具、简单场景 生产环境、API 服务

其他常见鉴权方法

/img/http-authentication-methods/0102.png
HTTP鉴权方法全景对比

1. Digest 认证

Digest 是 Basic 的改进版,不直接传密码,而是传密码的哈希值。

格式:

Authorization:Digest username="admin", realm="api", nonce="...", uri="/data", response="..."

流程:

  1. 客户端请求资源
  2. 服务端返回 401 + nonce(随机数)
  3. 客户端用密码 + nonce 计算 MD5,发送 response
  4. 服务端用相同方法验证

优点:比 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 的一部分。

流程:

  1. 用户授权第三方应用访问资源
  2. 第三方拿到 Access Token
  3. 用 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 是浏览器自动带的,有 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/