首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >HTTP用户基本认证

HTTP用户基本认证

作者头像
YaoQi
发布2025-07-14 19:09:43
发布2025-07-14 19:09:43
10200
代码可运行
举报
运行总次数:0
代码可运行

本篇介绍下HTTP对用户进行用户名密码的基本验证过程。

01—验证原理

浏览器遇到服务器响应需要Basic验证时,会跳出一个小窗口用来输入用户名和密码,如果没有携带此header头信息服务器端会返回401状态码,并携带header头信息:

代码语言:javascript
代码运行次数:0
运行
复制
WWW-Authenticate: Basic realm="Access to the staging site"

此信息用来告诉客户端需要验证,使用Basic方式。

realm是一个保护区域的描述,可省略。

接下来浏览器要要做基本认证请求,需要携带一个HTTP头信息:

代码语言:javascript
代码运行次数:0
运行
复制
Authorization: Basic dGlueWhhcmU6MTIzNDU2

Basic后是base64编码的用户名和密码,原文是:tinyhare:123456,原文应使用utf8编码。

之后用户名密码会保存到后台,每次给对应的服务器发请求都会自动带上。

注销验证一般需要服务器返回401,WWW-Authenticate: Basic 。

所以浏览器如果需要类似注销的操作,需要访问一个永远返回401的链接(需要服务器端支持),或者向服务器提交一个错误的验证(客户端可以自己解决)。

02—示例程序

此示例使用FastAPI实现,没有过FastAPI的读者建议先学习一些基本的用法,知道怎样配置响应内容,知道Depends函数能在请求到达后提前帮你处理一些问题(这里是用来处理认证相关的东西)。

安装依赖,我使用的是python3

代码语言:javascript
代码运行次数:0
运行
复制
pip3 install uvicorn fastapi aiofiles

源码:auth_basic.py

代码语言:javascript
代码运行次数:0
运行
复制
#! python3
import secrets
import hashlib
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from starlette.responses import Response,RedirectResponse

from fastapi.responses import HTMLResponse

app = FastAPI()

security = HTTPBasic(auto_error=False) # 一定要关掉自动错误,我们手动处理

class GetUsername:
    def __init__(self, auto_error: bool = True):
        self.auto_error = auto_error

    def __call__(self, credentials: HTTPBasicCredentials = Depends(security)):
        username = None
        if credentials:
            username = credentials.username
            password = hashlib.md5((credentials.password+"salt").encode('utf8')).hexdigest()
            # 这里应该从数据库获取用户信息,密码应该存储加盐计算的散列值,这里用的md5算法
            db_username = "tinyhare"  
            db_password = '207acd61a3c1bd506d7e9a4535359f8a' # password is 123456
            chek_username = secrets.compare_digest(username, db_username)
            chek_password = secrets.compare_digest(password, db_password)
            if not (chek_username and chek_password):
                username = None

        if username == None and self.auto_error:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Incorrect email or password",
                headers={"WWW-Authenticate": "Basic"},
            )
        return username

get_current_username = GetUsername() # 自动返回认证错误 
get_current_username2 = GetUsername(auto_error = False)#不自动返回认证错误

@app.get("/", response_class=HTMLResponse)
def read_current_user(username: str = Depends(get_current_username)):
    return '''<!DOCTYPE html>
    <html>
    <head>
        <script src="https://cdn.bootcss.com/bowser/1.9.4/bowser.min.js"></script>
        <script src="https://code.jquery.com/jquery-1.11.3.js"></script>
        <script src="/logout.js"></script>
    </head>
    <body>
        <h1>Hello ''' + username + ''',</h1>
        <a href="/logout">Logout link</a><br><br>
    <button type="button" onclick="logout('/')">Logout js</button>
    </body>
    </html>'''

@app.get("/logout")
def logout(username: str = Depends(get_current_username2)):
    if username: #认证状态下主动返回401,使浏览器删除认证信息
        response = Response(headers={"WWW-Authenticate": "Basic"}, status_code=401)
    else:  #非认证状态下直接跳转到某个地址 
        response = RedirectResponse(url="/")
    return response

源码:logout.js

代码语言:javascript
代码运行次数:0
运行
复制
function logout(redirUrl) {
  secUrl = window.location.href
  alert("You will logout from " + bowser.name)
  if (bowser.msie) {
    document.execCommand('ClearAuthenticationCache', 'false');
  } else if (bowser.gecko || bowser.blink) {
    $.ajax({
    async: false,
    url: secUrl,
    type: 'GET',
    username: 'logout'
    });
  } else if (bowser.webkit) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET", secUrl, true);
    xmlhttp.setRequestHeader("Authorization", "Basic logout");
    xmlhttp.send();
  } else {
    alert("Logging out automatically is unsupported for " + bowser.name
    + "You must close the browser to log out.");
  }
  setTimeout(function () {
    window.location.href = redirUrl;
  }, 200);
}

启动:

代码语言:javascript
代码运行次数:0
运行
复制
uvicorn --host 0.0.0.0 --port 8000 auth_basic:app --reload

访问:用户名tinyhare,密码123456

图片
图片

注:如果使用Logout link,请不要输入正确的用户名和密码,否则就又一次认证了。

带有认证的请求:

图片
图片

没有认证的请求(浏览器弹出认证窗口后点取消):

图片
图片

可以使用curl模拟请求,这样更直观:

代码语言:javascript
代码运行次数:0
运行
复制
正常认证
curl -svo /dev/null 'http://192.168.56.109:8000/' -H 'Authorization: Basic dGlueWhhcmU6MTIzNDU2'
不带认证,或错误认证
curl -svo /dev/null 'http://192.168.56.109:8000/' 
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-01-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 漫跑的小兔 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档