十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Iris 实战:基于 MySQL 数据库与 Docker 的 BasicAuth 认证示例深度解析

Iris 实战:基于 MySQL 数据库与 Docker 的 BasicAuth 认证示例深度解析 【免费下载链接】irisThe fastest HTTP/2 Go Web Framework. New, modern and easy to learn. Fast development with Code you control. Unbeatable cost-performance ratio :rocket:项目地址https://gitcode.com/gh_mirrors/ir/iris点击查看免费下载本篇文章围绕 Iris 官方示例_examples/auth/basicauth/database展开完整解析BasicAuth 中间件 MySQL 用户表 Docker 一键编排的落地方式。通过阅读本文你将掌握如何用basicauth.New 自定义Allow回调把认证数据源从静态列表切换到关系型数据库理解中间件内部的凭据校验链路与ctx.User()取值机制并能独立搭建出可复制的 Docker/手动两种运行环境。示例概述为什么需要数据库版 BasicAuthIris 内置的basicauth中间件默认支持两种静态认证数据源Default(users)直接在代码里写死map[string]string{username: password}或用户结构体切片Load(users.yml)/AllowUsersFile从 YAML/JSON 文件加载用户列表。这两种方式适合原型与小型应用但当用户量增长、账号需要后台管理时就必须把用户数据放进数据库。本示例正是官方给出的数据库化参考实现认证仍由basicauth中间件完成但用户数据的来源改为 MySQL 中的users表并且配套提供 Dockerfile 与 docker-compose.yml一条命令即可拉起 MySQL 应用两个容器。示例目录结构如下均相对于仓库根目录_examples/auth/basicauth/database/ ├── migration/db.sql # MySQL 建库、建表、插入演示账号 ├── Dockerfile # 多阶段构建应用镜像 ├── docker-compose.yml # MySQL 应用服务编排 ├── go.mod / go.sum # 模块依赖Iris v12 mysql driver ├── main.go # 应用入口数据库连接与认证逻辑 └── README.md # 官方快速上手文档快速开始一Docker 一键启动示例提供了完整的容器化方案前提是本地已安装 Docker。在_examples/auth/basicauth/database目录下执行$ docker-compose up --build这条命令会依次完成以下工作启动 MySQL 服务docker-compose.yml中使用官方mysql镜像并指定--default-authentication-pluginmysql_native_password兼容旧版客户端认证插件自动导入数据库结构将./migration目录挂载到容器的/docker-entrypoint-initdb.dMySQL 首次初始化时会自动执行其中的db.sql建库、建表、插入账号构建并启动应用基于 Dockerfile 将 Go 应用编译为静态二进制后放入scratch精简镜像映射8080:8080应用与数据库建立依赖关系app服务通过depends_on依赖db并配置了健康检查curl -f tcp://db:3306失败时restart: on-failure自动重试。其中app服务的环境变量与 MySQL 容器保持一致保证应用能连上数据库environment: PORT: 8080 MYSQL_USER: user_myapp MYSQL_PASSWORD: dbpassword MYSQL_DATABASE: myapp MYSQL_HOST: db值得注意容器内MYSQL_HOST是db服务名而手动运行时MYSQL_HOST是localhost这正是编排内网互通与本机直连两种场景的差异所在。快速开始二手动运行不带 Docker若本机已安装 Go 与 MySQL可在_examples/auth/basicauth/database目录下直接运行$ go run -modmod main.go # 或先编译再运行 $ go build -modmod手动模式需要自行准备 MySQL 环境以下四个环境变量会被应用读取均有默认值兜底环境变量默认值含义MYSQL_USERuser_myapp连接 MySQL 使用的用户名MYSQL_PASSWORDdbpassword上述用户的密码MYSQL_HOSTlocalhostMySQL 主机地址MYSQL_DATABASEmyapp目标数据库名设置方式示例export MYSQL_USERuser_myapp export MYSQL_PASSWORDdbpassword export MYSQL_HOSTlocalhost export MYSQL_DATABASEmyapp之后将 migration/db.sql 下载或直接引用并在你的 MySQL 实例上执行完成建库建表与数据初始化。数据库结构与演示账号db.sql的内容非常直白创建myapp数据库utf8mb4 字符集重建users表并插入两条演示记录CREATE DATABASE IF NOT EXISTS myapp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE myapp; CREATE TABLE users ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(255) NOT NULL, password varchar(255) NOT NULL, email varchar(255) NOT NULL, PRIMARY KEY (id) ); INSERT INTO users (username,password,email) VALUES (admin, admin, kataras2006hotmail.com), (iris, iris_password, iris-gooutlook.com);应用启动后访问 http://localhost:8080浏览器会弹出 Basic Auth 登录框官方预置了两组可用凭据username: admin password: adminusername: iris password: iris_password验证成功时页面会返回当前登录用户的 JSON 信息见下文index处理器。核心代码逐段解析main.go1. 用户结构体实现 basicauth.User 接口示例中用户模型是一个普通结构体通过db标签与users表列对应type User struct { ID int64 db:id json:id Username string db:username json:username Password string db:password json:password Email string db:email json:email } func (u User) GetUsername() string { return u.Username } func (u User) GetPassword() string { return u.Password }关键点在于GetUsername/GetPassword两个方法——它们在 middleware/basicauth/user.go 中被定义为basicauth.User接口的全部要求type User interface { context.UserGetUsername context.UserGetPassword }也就是说只要你的结构体提供这两个方法返回string中间件就能把它当作可识别的用户对象传递下去同时你依然可以保留Email等任意扩展字段。2. 连接 MySQLDSN 与环境变量main函数开头通过fmt.Sprintf拼接数据源名称DSN四个值全部来自环境变量缺失时回退到默认值dsn : fmt.Sprintf(%s:%stcp(%s:3306)/%s?parseTimetruecharsetutf8mb4collationutf8mb4_unicode_ci, getenv(MYSQL_USER, user_myapp), getenv(MYSQL_PASSWORD, dbpassword), getenv(MYSQL_HOST, localhost), getenv(MYSQL_DATABASE, myapp), ) db, err : connect(dsn) if err ! nil { panic(err) }getenv是示例自带的兜底工具函数环境变量为空时返回默认值。connect则使用标准库database/sql加 MySQL 驱动_ github.com/go-sql-driver/mysql打开连接并立即Ping验证连通性失败则关闭连接并返回错误func connect(dsn string) (*database, error) { conn, err : sql.Open(mysql, dsn) if err ! nil { return nil, err } err conn.Ping() if err ! nil { conn.Close() return nil, err } return database{conn}, nil }database类型只是对*sql.DB的轻量封装便于挂载自定义查询方法。3. 认证核心自定义 Allow 回调这是整个示例最值得借鉴的部分。basicauth.Options.Allow是唯一必填字段它是一个函数类型见 middleware/basicauth/basicauth.gotype AuthFunc func(ctx *context.Context, username, password string) (any, bool)示例用数据库查询来实现这个回调拿到用户输入的用户名密码后去users表里精确匹配查到即返回该用户对象和trueallowFunc : func(ctx iris.Context, username, password string) (any, bool) { user, err : db.getUserByUsernameAndPassword(context.Background(), username, password) return user, err nil } opts : basicauth.Options{ Realm: basicauth.DefaultRealm, ErrorHandler: basicauth.DefaultErrorHandler, Allow: allowFunc, } auth : basicauth.New(opts)对应的查询方法使用参数化 SQL?占位符避免字符串拼接带来的注入风险func (db *database) getUserByUsernameAndPassword(ctx context.Context, username, password string) (User, error) { query : fmt.Sprintf(SELECT * FROM %s WHERE %s ? AND %s ? LIMIT 1, users, username, password) rows, err : db.QueryContext(ctx, query, username, password) // ...rows.Scan(user.ID, user.Username, user.Password, user.Email) }中间件创建完成后通过app.Use(auth)挂载为全局处理器并注册首页路由app : iris.New() app.Use(auth) app.Get(/, index) app.Listen(:8080)4. 获取当前用户ctx.User()认证通过后中间件会把Allow返回的用户对象存入请求上下文。处理器内通过ctx.User().GetRaw()还原出原始类型func index(ctx iris.Context) { user, _ : ctx.User().GetRaw() // user is a type of main.User ctx.JSON(user) }这段代码背后有一套通用用户抽象context.User()返回 context/context_user.go 中定义的User接口提供GetRaw、GetUsername、GetPassword等一组Get*方法。当你传入的自定义结构体没有完整实现该接口时中间件会自动用UserPartial包装它SetUser内部完成而GetRaw始终能拿到最原始的实例因此这里可以直接断言为main.User。中间件源码级原理一次认证请求发生了什么结合 middleware/basicauth/basicauth.go 中的serveHTTP一次完整的认证请求链路如下读取并解析 Authorization 头decodeHeader见 middleware/basicauth/header.go校验头部是否以Basic开头随后 base64 解码并以:分隔出用户名与密码。该函数同时拒绝含:的用户名/密码RFC 规定用户名不得包含冒号头部缺失或格式错误触发ErrCredentialsMissing交给ErrorHandler处理。DefaultErrorHandler见 middleware/basicauth/error.go会写入WWW-Authenticate: Basic realmAuthorization Required响应头并返回 401浏览器据此弹出登录框调用 Allow 校验即示例中的allowFunc去数据库查询匹配校验失败返回 401 并重新质询MaxTries 0时还会累计失败次数用 Cookie 或 Session 记录达到阈值后改发 403 Forbidden校验成功将用户对象SetUser到上下文把logout函数注册为SetLogoutFunc然后ctx.Next()放行后续处理器内存凭据缓存中间件内部维护credentials map[string]*time.Timekey 为username:password结合MaxAge控制过期时间可选GC配置定时清理旧条目避免长期运行内存膨胀。Options中与本示例直接相关的字段语义如下Realm质询提示语DefaultRealm Authorization RequiredAllow必填的认证函数本示例将其指向数据库查询ErrorHandler凭据失败的统一处理入口默认即DefaultErrorHandler。此外New会在opts.Allow nil时直接panic(BasicAuth: Allow field is required)从源头保证中间件配置完整性。安全注意与扩展方向官方 README 特别声明示例不包含向数据库添加用户的代码这超出了中间件的职责范围由终端开发者自行扩展。基于仓库源码可以给出以下安全与扩展建议密码存储示例为演示起见在users表明文存密码。生产环境应改用 bcrypt 哈希存储——basicauth已内置BCRYPT选项basicauth.BCRYPT通过Default(users, basicauth.BCRYPT)或AllowUsers(users, basicauth.BCRYPT)即可启用哈希比对见 middleware/basicauth/user.go传输安全Basic Auth 的凭据仅做 base64 编码是可逆的明文传输下极易被窃听。中间件提供Options.HTTPSOnly开关开启后任何非 HTTPS 请求都会被直接以 505 状态码拒绝对应ErrHTTPVersion限流防爆破Options.MaxTries可限制登录失败次数配合MaxTriesCookie或MaxTriesSession达到上限后返回 403用户管理如需注册/改密功能可参照migration/db.sql的表结构自行实现 INSERT/UPDATE 接口或复用仓库中 mysql 数据库示例 的 service/repository 分层思路。小结本示例的价值在于展示了basicauth中间件的数据源可插拔性认证协议Basic Auth 头部解析、401 质询、用户上下文注入由中间件统一负责而账号从哪来完全由Allow回调决定。无论是 Docker 一键编排还是手动go run你都可以在几分钟内得到一个Iris MySQL BasicAuth的最小可运行认证服务并以此为基础扩展出完整的用户体系。关键文件速查示例 README官方快速上手文档main.go数据库连接与Allow回调实现migration/db.sql建库建表与演示账号docker-compose.ymlMySQL 应用编排middleware/basicauth/basicauth.go中间件核心实现Options、New、serveHTTPcontext/context_user.goUser接口与ctx.User()取值机制。赞分享【免费下载链接】irisThe fastest HTTP/2 Go Web Framework. New, modern and easy to learn. Fast development with Code you control. Unbeatable cost-performance ratio :rocket:项目地址https://gitcode.com/gh_mirrors/ir/iris点击查看免费下载相关推荐TanStack Start 集成 Supabase 实战基于 React 的全栈认证与数据获取示例解析TanStack Start 集成 Supabase 实战基于 React 的全栈认证与数据获取示例解析 本文以仓库 examples/react/start前端路由SSRLeptos Axum 会话认证实战session_auth_axum 示例深度解析Leptos Axum 会话认证实战session_auth_axum 示例深度解析 导读 本文以 Leptos 仓库中的 session_auth_ax前端后端Web框架SSRDORA 与 ROS2 互通实战基于 C 的 turtlesim 数据流示例cxx-ros2-dataflow深度解析DORA 与 ROS2 互通实战基于 C 的 turtlesim 数据流示例cxx ros2 dataflow深度解析 本篇文章围绕 DORADat机器人人工智能ROS消息路由上一篇FastGPT 性能测试报告并发处理与响应时间分析下一篇NuGet.Client插件开发终极指南如何扩展NuGet.Protocol与自定义包源协议创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表