
后端【免费下载链接】ihp The fastest way to build type safe web apps. IHP is a new batteries-included web framework optimized for longterm productivity and programmer happiness项目地址https://gitcode.com/gh_mirrors/ih/ihp点击查看免费下载本指南以 IHP 官方文档 Guide/oauth.markdown 为主体系统讲解如何在 IHP 应用中接入 Google 与 GitHub 两种 OAuth 第三方登录。你将掌握从启用ihp-oauth-google/ihp-oauth-github包、修改数据库 Schema、编写 Controller、配置路由与 FrontController、注入环境变量到在登录页渲染第三方登录按钮的完整流程并了解底层 Nix 包管理机制与常见的 Docker 部署排障方法。概览IHP 的 OAuth 支持在常规的邮箱密码登录之外IHP 还提供了基于第三方身份提供商的 OAuth 登录能力。OAuth 登录功能属于IHP Pro范畴这一点在配置前需要明确——免费社区版不包含该功能。目前 IHP 官方支持的身份提供商有两个Google通过ihp-oauth-google包提供GitHub通过ihp-oauth-github包提供两个提供商的接入路径高度一致启用 Haskell 包 → 修改users表 Schema → 创建 OAuth Controller → 注册路由与 FrontController → 配置Config/Config.hs与start脚本中的环境变量 → 测试登录 →可选在登录页添加按钮。下面分别展开。前置知识IHP 的 Haskell 依赖注入机制在动手之前先理解 OAuth 包是如何进入应用的。IHP 基于 Nix 管理依赖项目内的flake.nix或传统default.nix通过haskellDeps声明 Haskell 层面的依赖。从仓库的 NixSupport/default.nix 可以看到依赖的最终去向allHaskellPackages (if withHoogle then ghc.ghcWithHoogle else ghc.ghcWithPackages) (p: haskellDeps p [ modelsPackage ]);也就是说你在haskellDeps中列出的每个包都会被打包进 GHC 环境随后在构建应用库时被纳入依赖见 NixSupport/default.nix 中libraryHaskellDepends [ base modelsPackage ] ... (haskellDeps ghc)。因此只要把ihp-oauth-google/ihp-oauth-github加入haskellDepsGHC 就能在编译期解析到IHP.OAuth.Google.*/IHP.OAuth.Github.*模块。需要说明的是ihp-oauth-google、ihp-oauth-github属于 IHP Pro 的私有包并未包含在本开源仓库的 overlay见 NixSupport/overlay.nix中——该 overlay 只列示了ihp-router、ihp-ide、ihp-mail等开源子包。你在项目中启用它们时包本身由 IHP Pro 渠道提供。接入 Google 登录Login with Google第一步启用ihp-oauth-google包打开项目根目录的flake.nix在haskellDeps列表中追加ihp-oauth-googlelet ihp .. haskellEnv import ${ihp}/NixSupport/default.nix { ihp ihp; haskellDeps p: with p; [ # ... ihp-oauth-google # ----- ADD THIS LINE ]; otherDeps p: with p; [ ]; projectPath ./.; }; in haskellEnv如果你的项目仍使用传统default.nix布局则在default.nix中做同样的修改GitHub 一节将展示这种写法。修改完成后停止本地开发服务器CTRL C运行devenv up重建开发环境并启动服务。devenv up是 IHP 开发环境的标准启动命令重建过程会由 direnv 自动触发参见 Guide/package-management.markdown。依赖较多时首次构建可能较慢之后会命中 Nix 二进制缓存。第二步Schema 变更Google OAuth 登录需要在users表上新增一个google_user_id TEXT列。该列必须允许为空nullable且默认值为 NULL——因为非 Google 注册的用户不会填写该字段。打开Application/Schema.sql在CREATE TABLE users语句中加入该列CREATE TABLE users ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, -- ... , google_user_id TEXT );保存后让 IHP 的 Schema 编译器重新生成模型代码IHP 开发服务器通常会自动监听 Schema 变化并触发代码生成。google_user_id将作为新用户模型字段出现供后续 Controller 读写。第三步创建 OAuth Controller新建文件Web/Controller/GoogleOAuth.hs内容如下module Web.Controller.GoogleOAuth where import Web.Controller.Prelude import Web.Controller.Sessions () import IHP.OAuth.Google.Controller import qualified IHP.OAuth.Google.Types as Google instance Controller Google.GoogleOAuthController where action Google.NewSessionWithGoogleAction newSessionWithGoogleAction User action Google.GoogleConnectCallbackAction googleConnectCallbackAction User instance GoogleOAuthControllerConfig User where beforeCreateUser user googleClaims user | set #isConfirmed True -- This will auto-confirm your users email这段代码定义了两个关键动作NewSessionWithGoogleAction用户点击使用 Google 登录时触发的入口动作由框架提供的newSessionWithGoogleAction User实现负责生成跳转到 Google 的链接并引导用户到 Google 授权页GoogleConnectCallbackActionGoogle 授权完成后回调的地址由googleConnectCallbackAction User处理回调参数、校验 ID TokenJWT、查找或创建User记录并建立会话。instance GoogleOAuthControllerConfig User则是可定制点beforeCreateUser在新用户落库前被调用。示例中通过set #isConfirmed True将新用户标记为已确认邮箱跳过邮箱确认流程若你的应用依赖邮箱确认应删除或修改这行。googleClaims参数携带 Google 返回的声明信息如邮箱、姓名、头像等可用于填充更多用户字段。第四步注册路由打开Web/Routes.hs分两步操作在文件顶部加入类型定义导入import IHP.OAuth.Google.Types在文件末尾启用 AutoRouteinstance AutoRoute GoogleOAuthControllerAutoRoute是 IHP 路由 DSL 的核心机制只要 Controller 类型实现了AutoRoute其全部 Action 就会自动生成/NewSessionWithGoogle、/GoogleConnectCallback等 URL 与路由解析。仓库的 integration-test/Web/Routes.hs 展示了同样的写法instance AutoRoute PostsController。第五步注册到 FrontController打开Web/FrontController.hs在文件顶部加入导入import IHP.OAuth.Google.Types import Web.Controller.GoogleOAuth将GoogleOAuthController加入控制器列表instance FrontController WebApplication where controllers [ startPage StartpageAction -- ... , parseRoute GoogleOAuthController -- ----- ADD THIS ]FrontController决定请求如何被分发到各 Controller对照 integration-test/Web/FrontController.hs 的controllers [ parseRoute PostsController ]写法可以理解parseRoute GoogleOAuthController即是将请求按 AutoRoute 规则解析并派发给该控制器。第六步修改 View Prelude由于 OAuth 控制器类型定义在IHP.OAuth.Google.Types而非常规的Web.Types需要把该模块重新导出以便在视图中直接写pathTo NewSessionWithGoogleAction而无需处处手动导入。修改Web/View/Prelude.hsmodule Web.View.Prelude ( module IHP.ViewPrelude -- ... , module IHP.OAuth.Google.Types -- ---- ADD THIS ) where import IHP.ViewPrelude -- ... import IHP.OAuth.Google.Types -- ---- ADD THISView Prelude相当于视图层的公共导入区项目所有Web/View/**/*.hs都隐式依赖它。这一步是 IHP 的类型导向设计使然让 OAuth 相关的 Action 类型在视图层全局可见。第七步配置 Google Client IDController 运行前必须配置 Google 客户端 ID其形如1234567890-abc123def456.apps.googleusercontent.com。你需要在 Google API 控制台创建项目并启用、配置 OAuth参考 Google 官方的 Get Google API Client ID 指南完成首次配置。拿到 Client ID 后打开Config/Config.hs添加导入import IHP.OAuth.Google.Config在config中调用initGoogleOAuthconfig :: ConfigBuilder config do option Development option (AppHostname localhost) initGoogleOAuth -- --- ADD THISinitGoogleOAuth会读取OAUTH_GOOGLE_CLIENT_ID环境变量并注入GoogleOAuthController。这一步与 IHP 的配置体系保持一致——从 Guide/config.markdown 可知IHP 使用类型化配置系统config :: ConfigBuilder内通过option设置各类配置项OAuth 初始化函数本质上也是一种配置声明。接着在项目的start脚本中定义本地环境变量# ... export OAUTH_GOOGLE_CLIENT_IDMY_GOOGLE_CLIENT_ID # -- ADD THIS LINE BEFORE THE RunDevServer CALL RunDevServer将MY_GOOGLE_CLIENT_ID替换为你的真实 Client ID。修改start后需要重启本地开发服务器环境变量才会生效。第八步试运行启动服务后访问http://localhost:8000/NewSessionWithGoogle点击Login with Google按钮应弹出 Google 登录对话框授权后自动回到应用并完成登录。如果 Google 显示错误信息先检查浏览器 JavaScript 错误控制台。一个常见原因是localhost:8000不在该 Client ID 的授权主机白名单host whitelist中需要到 Google API 控制台把本地开发地址加入 OAuth 重定向/授权域名列表。可选在登录页加入 Login with Google 按钮直接跳转 URL 的体验并不好更常见的做法是在现有登录页放置一个按钮。打开Web/Sessions/New.hs这是邮箱密码登录视图参见 Guide/authentication.markdown 的NewView User模式module Web.View.Sessions.New where import Web.View.Prelude import IHP.AuthSupport.View.Sessions.New instance View (NewView User) where html NewView { .. } [hsx| div classh-100 idsessions-new div classd-flex align-items-center div classw-100 div stylemax-width: 400px classmx-auto mb-5 h5Please login/h5 {renderForm user} {loginWithGoogle} !-- ADD THIS CALL HERE -- /div /div /div /div |] -- ... loginWithGoogle :: Html loginWithGoogle [hsx| div idg_id_onload >function onGoogleLogin(response) { var form document.getElementById(new-session-with-google-form); form.querySelector(input[namejwt]).value response.credential; form.submit(); }该脚本把 GSI 回调返回的response.credentialJWT写入表单隐藏字段并提交。注意googleClientId中的YOUR GOOGLE CLIENT ID占位符需替换为真实值。完成上述改动后即可从常规登录页使用 Google 登录。排障Docker/Nix 镜像中的证书问题如果 Google 登录在本机正常、但在 Nix 构建的 Docker 容器内失败报错形如HttpExceptionRequest ... (InternalException (HandshakeFailed (Error_Protocol certificate has unknown CA UnknownCa)))则镜像很可能缺少根 CA 证书。详见 Guide/deployment.markdown 中 TLS certificates in Nix-built Docker images 一节dockerTools.buildImage产出的最小镜像默认不含/etc/ssl/certs需要在构建镜像时引入caCertificates、fakeNss等包并在容器环境变量中设置Env [ SSL_CERT_FILE/etc/ssl/certs/ca-certificates.crt NIX_SSL_CERT_FILE/etc/ssl/certs/ca-certificates.crt SSL_CERT_DIR/etc/ssl/certs ];由于 OAuth 回调与令牌校验都需要向 Google/GitHub 发起 HTTPS 请求缺少 CA 证书会让 TLS 握手失败这是部署阶段最典型的 OAuth 故障之一。接入 GitHub 登录Login with GitHubGitHub 登录的接入路径与 Google 完全对称差异在于数据列类型为INT、需要 Client ID 与 Client Secret 两个凭据、以及 GitHub 回调采用标准 OAuth 重定向流程而非 GSI 前端 SDK。第一步启用ihp-oauth-github包打开项目的default.nix在haskellDeps中追加ihp-oauth-githublet ihp .. haskellEnv import ${ihp}/NixSupport/default.nix { ihp ihp; haskellDeps p: with p; [ # ... ihp-oauth-github # ----- ADD THIS LINE ]; otherDeps p: with p; [ ]; projectPath ./.; }; in haskellEnv同样地停止开发服务器后运行devenv up完成安装。第二步Schema 变更GitHub 需要github_user_id INT列。文档示例额外给出了DEFAULT NULL UNIQUE约束保证同一 GitHub 账号只能绑定一个本地用户CREATE TABLE users ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, -- ... , github_user_id INT DEFAULT NULL UNIQUE, );注意 Google 一节是google_user_id TEXTGitHub 一节是github_user_id INTGoogle 的 sub 是字符串而 GitHub 的用户 ID 是整数。两者都要求可空、默认 NULL。第三步创建 OAuth Controller新建Web/Controller/GithubOAuth.hsmodule Web.Controller.GithubOAuth where import Web.Controller.Prelude import Web.Controller.Sessions () import IHP.OAuth.Github.Controller import qualified IHP.OAuth.Github.Types as Github instance Controller Github.GithubOAuthController where action Github.NewSessionWithGithubAction newSessionWithGithubAction User action Github.GithubConnectCallbackAction githubConnectCallbackAction User instance GithubOAuthControllerConfig User where beforeCreateUser user githubUser user | set #isConfirmed True -- This will auto-confirm your users email. Remove this line if you dont use email confirmation afterCreateUser user do -- Called after a new user is created -- E.g. you could send a welcome email here: -- -- sendMail WelcomeMail { .. } -- pure () beforeLogin user githubUser do -- Called before the user is logged in -- Here you can e.g. set the apps profile picture to the one provided by github: -- -- user -- | setJust #profilePicture githubUser.avatarUrl -- | setJust #githubName githubUser.login -- | pure -- pure user相比 Google 版本GitHub 的GithubOAuthControllerConfig提供了三个生命周期钩子注释中的用法示例值得展开beforeCreateUser user githubUser新用户落库前调用示例将isConfirmed置为True不启用邮箱确认时保留否则删除afterCreateUser user新用户落库后调用典型用途是发送欢迎邮件如sendMail WelcomeMail { .. }默认pure ()表示什么都不做beforeLogin user githubUser用户登录前调用可把 GitHub 提供的头像、用户名同步到本地用户例如setJust #profilePicture githubUser.avatarUrl、setJust #githubName githubUser.login最后返回修改后的user。这与邮箱登录的beforeLogin钩子见 Guide/authentication.markdown设计一致。第四步注册路由打开Web/Routes.hs顶部导入import IHP.OAuth.Github.Types末尾启用 AutoRouteinstance AutoRoute GithubOAuthController第五步注册到 FrontController打开Web/FrontController.hs顶部导入import IHP.OAuth.Github.Types import Web.Controller.GithubOAuth加入控制器列表instance FrontController WebApplication where controllers [ startPage StartpageAction -- ... , parseRoute GithubOAuthController -- ----- ADD THIS ]第六步修改 View Prelude与 Google 同理在Web/View/Prelude.hs重新导出 OAuth 类型模块module Web.View.Prelude ( module IHP.ViewPrelude -- ... , module IHP.OAuth.Github.Types -- ---- ADD THIS ) where import IHP.ViewPrelude -- ... import IHP.OAuth.Github.Types -- ---- ADD THIS这样视图层就能直接书写pathTo NewSessionWithGithubAction这类调用而无需逐文件手动导入。第七步配置 Client ID 与 Client Secret先按 GitHub 官方指南创建 GitHub App 并获取 Client ID 与 Secret。创建时需提供Callback URL设置为http://localhost:8000/GithubConnectCallback——该地址必须与GithubConnectCallbackAction的实际路径严格一致。拿到凭据后打开Config/Config.hs添加导入import IHP.OAuth.Github.Config调用initGithubOAuthconfig :: ConfigBuilder config do option Development option (AppHostname localhost) initGithubOAuth -- --- ADD THISinitGithubOAuth会读取OAUTH_GITHUB_CLIENT_ID与OAUTH_GITHUB_CLIENT_SECRET两个环境变量并传给GithubOAuthController。接着在项目的start脚本中添加# ... export OAUTH_GITHUB_CLIENT_IDMY_GITHUB_CLIENT_ID # -- ADD THIS LINE BEFORE THE RunDevServer CALL export OAUTH_GITHUB_CLIENT_SECRETMY_GITHUB_SECRET RunDevServer将MY_GITHUB_CLIENT_ID与MY_GITHUB_SECRET替换为真实值然后重启本地开发服务器。第八步试运行与按钮接入访问http://localhost:8000/NewSessionWithGithub点击Login with Github按钮浏览器会重定向到 GitHub 授权页授权后回到应用完成登录。在任意页面放置 Continue with GitHub 按钮只需链接到NewSessionWithGithubActiona href{NewSessionWithGithubAction} target_self classbtn btn-primary Continue with GitHub /a务必使用target_selfIHP 默认启用 Turbolinks若省略该属性Turbolinks 的拦截会干扰浏览器向 GitHub 发起的整页重定向导致授权流程异常。这是 GitHub 接入中最容易踩的坑之一。两种 Provider 的对照速查维度GoogleGitHub启用包ihp-oauth-googleihp-oauth-github用户表新增列google_user_id TEXT可空默认 NULLgithub_user_id INT DEFAULT NULL UNIQUEController 模块Web/Controller/GoogleOAuth.hsWeb/Controller/GithubOAuth.hsTypes 导入IHP.OAuth.Google.TypesIHP.OAuth.Github.Types入口 ActionNewSessionWithGoogleActionURL/NewSessionWithGoogleNewSessionWithGithubActionURL/NewSessionWithGithub回调 ActionGoogleConnectCallbackActionGithubConnectCallbackActionCallback URLhttp://localhost:8000/GithubConnectCallback环境变量OAUTH_GOOGLE_CLIENT_IDOAUTH_GITHUB_CLIENT_ID、OAUTH_GITHUB_CLIENT_SECRET初始化函数initGoogleOAuthinitGithubOAuth前端机制Google Login JS SDKGSIgoogle-login.js回调纯服务端重定向按钮用a链接可定制钩子beforeCreateUserbeforeCreateUser、afterCreateUser、beforeLogin关键机制回顾与常见问题AutoRoute 与 FrontController 的协作instance AutoRoute GithubOAuthController负责把 Controller 的每个 Action 映射为 URLparseRoute GithubOAuthController则把该 Controller 挂载进请求分发链。两者缺一不可且都遵循仓库 integration-test/Web/Routes.hs 与 integration-test/Web/FrontController.hs 展示的标准 IHP 项目模式。环境变量缺失的症状如果initGoogleOAuth/initGithubOAuth已调用但start脚本未导出对应变量Controller 初始化时读不到凭据登录入口会报错或直接不可用。修改环境变量后必须重启 dev server。生产部署提示文档示例均以localhost开发环境为基准。生产环境需要把Config/Config.hs中的AppHostname与option Production切换为真实域名参见 Guide/config.markdown并在 Google 控制台 / GitHub App 设置中将生产域名加入授权列表、更新 Callback URL同时按上文所述为 Nix 构建的 Docker 镜像补齐 CA 证书避免 HTTPS 回调握手失败。IHP Pro 边界OAuth 登录含本指南涉及的两个包依赖 IHP Pro 授权。开源仓库本身只提供框架核心与社区子包见 NixSupport/overlay.nix接入前请确认你的许可证与订阅状态。至此你的 IHP 应用已经同时具备 Google 与 GitHub 两种第三方登录能力可与 Guide/authentication.markdown 中的邮箱密码登录体系并存共同服务于完整的用户认证闭环。赞分享后端【免费下载链接】ihp The fastest way to build type safe web apps. IHP is a new batteries-included web framework optimized for longterm productivity and programmer happiness项目地址https://gitcode.com/gh_mirrors/ih/ihp点击查看免费下载相关推荐3步让老Mac装上新版macOSOpenCore Legacy Patcher 免费完整教程3步让老Mac装上新版macOSOpenCore Legacy Patcher 免费完整教程 OpenCore Legacy Patcher下称 OCLP操作系统固件驱动开发Amplication第三方登录GitHub、Google OAuth集成实战指南Amplication第三方登录GitHub、Google OAuth集成实战指南 引言为什么需要第三方登录 在现代Web应用中用户认证是必不可少的功能后端代码生成低代码AI 应用Flagsmith OAuth 登录配置指南接入 Google 与 GitHub 身份提供商Flagsmith OAuth 登录配置指南接入 Google 与 GitHub 身份提供商 本篇指南讲解如何在自托管 Flagsmith 实例上启用基于 O后端前端上一篇如何用MusePose快速生成虚拟人舞蹈视频完整指南与实战技巧下一篇10分钟掌握时序数据库压测用autocannon对比InfluxDB与TimescaleDB性能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考