Auth与用户系统

  • 项目目的: 1, 打造"多用户"站点 2, 防被人恶意攻击

自建token认证

  • jwt
  • CSRF
  • cors
  • CA机构, 自签名证书, let's encrypt
  • SameSite=Lax
  • access token: 1h/短期/api操作, refresh token: 7天/签发access token
  • 风险几乎总是伴随着“状态”(登录态)和“动作”(写操作)而来
  • “‘网址保密’/个人使用的工具,没有攻击者注意到我”​​:​​这是一种非常有效的安全策略,称为“通过隐匿实现安全”(Security through obscurity)
  • 几个安全项检查:
    • 设置cors为二级域名, 而非CORS(app)
    • set_cookie时: secure=True,samesite="Lax", httponly=True, domain为.102434.xyz
    • peewee, 防sql注入
    • refresh token和access token机制: 高频使用的access token随时丢掉换新的
    • csrf -> 因为我确保无ugc内容, 所以没启用, 心智成本高/麻烦, 且各个站都没用csrf
  • XSS: crosssite scripting
  • mkcert: 本地127.0.0.1加上https

现成方案

  • 可行的
    • clerk, kinde, supabase auth, auth0
  • 放弃的
    • casdoor: 过于复杂
    • pocketbase/firebase: 后端全家桶方案
    • authing: 国内产品, 8k MAU, 99月费后10k MAU
    • python: authlib: 需要自己写login接口
    • Keycloak: 高度和java绑定? 基本看不到react下的sdk
    • Cognito: aws
    • authelia: 非面向用户, 认证网关
    • lucia auth: 只是基于session, 不具备oauth, 且已被废弃/代码保留用于学习参考
    • openauth: 只做认证(通过or not), 不处理会话相关, 身份验证界面要自己写, 无法拿到用户信息
    • auth.js: nextauth改名auth.js: 需要自己新建完整的postgre schema才能获取用户信息功能, 默认只能jwt认证
    • better auth: ts生态的, 且需要漫长而复杂的数据库创建等步骤
    • firebase: 如果不使用其他生态的话, 它的sdk和接入有点重
    • zitadel: 偏向网关
    • logto: 需要实现登录登出路由
    • Auth0(收费贵)
    • stackauth(较新), 有免费方案, 部署文档中警告很多
    • supertokens: sdk文档界面很差, 是个java项目

平台调研

  • Auth0这类现成方案
  • supabase(firebase替代/全栈方案), firebase(重型全家桶), pocketbase(前端+go), auth.js(只对接前端), supertokens(基于java/内存开销大, 开源)
  • supabase pricing: 50k月度活跃用户
  • auth0 pricing: 25k月活跃用户
  • clerk: 10kMAU
  • auth0: b站28页结果(但很少是auth0, 精确匹配结果很少), supabase: 10页结果
    • supabase的反馈实测说开源极其糟糕/跑起来都很难, 开源只是噱头
  • "sso 开源": 允许用户只登录一次即可访问多个应用程序或系统
    • casdoor: 轻量sso方案/1panel可直接安装
  • logto: 有中文页, 50k MAU, 1panel提供下载
    • casdoor b站搜索结果7条(1/4页), logto 2条,
  • 尝试中:
    • Auth0
    • casdoor
    • logto
  • sdk:

casdoor

  • 组织
    • 内置组织
    • 其他组织
  • 用户
  • 应用
  • 提供者
    • 多种第三方提供者
  • OIDC, OAuth, SAML
  • 不需要在你的Flask或React代码里处理用户注册、登录、修改密码这些繁琐又容易出错的事情
    • 你只需要告诉Casdoor:“嘿,我有一个应用(Application),用户在你那里登录成功后,请告诉我用户是谁就行了”
  • 前端:
    • 提供一个“登录”按钮。
    • 点击后,引导用户跳转到Casdoor的登录URL(这个URL需要用你的clientId, redirectUri等参数拼装)。
    • 提供一个 /auth/callback 页面,用于接收Casdoor返回的授权码(code)。
    • 收到code后,将其发送给你的Flask后端。
  • Casdoor的工作​​:
    • 展示登录页,处理认证逻辑。认证成功后,将用户浏览器重定向回redirectUri,并附上一个code
  • 后端(Flask)的工作​​:
    • 提供一个API接口(如 /api/login_with_casdoor)。
    • 这个接口接收前端发来的code。
    • 用这个code、你的clientId和clientSecret,​​在后端​​偷偷地向Casdoor的令牌端点(Token Endpoint)发送请求,换取最终的AccessToken和用户信息(如用户名、ID等)。
    • 这一步是关键!​​ 之所以要在后端做,是为了保护clientSecret。
    • 拿到用户信息后,你可以在Flask的Session里标记这个用户已登录,或者给你的前端签发一个你自己生成的JWT(这样你就完全掌控了JWT,而不是依赖Casdoor的JWT)
  • better auth
    • clerk
    • next-auth
    • stack auth
    • lucia auth
    • openauth
  • 组成部分:
    • verification: 验证用户是它们声称的
      • 登录: 用户名密码, passkey, oauth
      • 后续: access/refresh token
    • user info: 拿到用户的信息: 邮箱/头像/权限
    • authentication UI: 登录按钮/登出按钮
  • 新技术
    • 云托管前端: vercel
    • serverless: vercel
    • 数据库云托管: supabase
  • 关于认知的变化/后端职责:
    • 直接login_required套在所有接口上, 权限不够直接拒绝
    • 你之前用Flask做全栈时,需要处理会话(Session)、渲染模板、处理登录表单,所以感觉复杂。现在剥离了前端,后端API的世界的确就应该是这么简单
  • Google服务会关闭吗? 会,但通常是用户数不多的边缘产品。像认证这种核心基础设施服务,被关闭的可能性极低。即使关闭,也会给出非常长的迁移周期和方案
    • ​​“新浪潮”服务(Clerk, Kinde)​​:可靠性需要评估​​:它们是VC投资的创业公司,存在理论上倒闭的风险
    • 50k MAU是什么规模?​​
      • ​​50k MAU(月活)是一个非常非常成功的个人项目/小型创业公司的规模​​。
      • 举个例子:一个50k MAU的产品,平均每天大约有 ​​1,600 - 2,000​​ 活跃用户。这已经是一个需要你开始认真考虑商业化、团队扩容和基础设施优化的阶段了。绝大多数Side Project和个人项目在整个生命周期内都达不到这个规模。
      • 因此,几乎所有认证服务的免费额度都足以覆盖你的起步和快速增长阶段,直到你的项目获得真正的成功。

clerk

  • 项目页
  • 前端用 getToken({ template: "backend" }) 从 Clerk 获取。这个 token 只能读,不能改

waline的改造

  • 自定义用户系统, 文档
  • 目的和需求:
    • 在.102434.xyz下登录后, 评论区无需登录, 且显示自己的头像和用户名
    • waline登录选项里, 登录时只能打开自己的登录页, 原先oauth不能用了(qq/github), 原先邮箱密码方式不能用了, 原先的个人信息页/修改操作都不能用了

cloudflared

Tunnel credentials written to /home/ubuntu/.cloudflared/2f33b438-b89b-42c3-93f8-ca77dd8424c2.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.

Created tunnel my-tunnel with id 2f33b438-b89b-42c3-93f8-ca77dd8424c2