鉴权接入

在应用里接入 Known 身份:Cookie SSO 面向人、Bearer 面向机器,两路互不越界。

最后更新

Known 服务端可裁剪出一套双鉴权:人(浏览器)走 Cookie 会话、机器(CLI / 第三方)走 Bearer Token。 两条通道同一份身份后端,但受众边界、CORS、scope 完全不同。

接入拓扑

一份身份后端对两类受众暴露两条通道,两路互不越界:

                       ┌─ /api/*     内部 BFF 面 · Cookie / SameSite=Lax  ← 浏览器(人)
浏览器 / 客户端 ──HTTPS──▶
                       └─ /api/v1/*  公开机器面 · Bearer / scope 白名单   ← CLI / 第三方(机器)
  • 作为接入方你不必关心身份后端跑在哪个进程:在同一 apex 域(*.known.org.cn)下,认证 Cookie 走 Domain=.known.org.cn,天然跨子域共享登录态(SSO),无需独立 auth 子域。
  • 机器面(/api/v1)只认 Bearer 令牌,绝不共享浏览器 Cookie;反之浏览器 Cookie 也进不了机器面白名单外的端点。

IAuthProvider 抽象:

[WebApi]
public interface IAuthProvider
{
    Task<Result<UserInfo>> CurrentAsync();
    Task<Result> SignInAsync(string email, string password, bool remember);
    Task<Result> SignOutAsync();
}

浏览器侧由 ASP.NET Core Cookie 中间件管理。登录成功后签发 Set-Cookie 带:

Domain=.known.org.cn; HttpOnly; SameSite=Lax; Secure; Max-Age=...

同域内(app 与自家 CLI 之外的所有 Known 子域)都自动带上;跨到 api.known.org.cn 时 SameSite=Lax 只在顶层导航发送、XHR 不带——所以机器面必须走 Bearer。

Bearer Token(机器)

/api/v1/* 只接 Bearer,三类令牌:

  • Personal Access Token (PAT) — 用户签发、给 CLI 用;带 scope(如 read / write / admin); 落库仅存 SHA-256 哈希,明文只在签发那一刻可见一次。
  • Client Credentials — 机器对机器,走标准 OAuth2 授权服务器;无交互。
  • Authorization Code (OIDC) — 第三方网页应用登录,宿主应用充当 OIDC Provider;consent 屏列 scope。

C# 客户端调用示例:

var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new("Bearer", patFromConfig);
var res = await http.GetFromJsonAsync<Result<PagedResult<Project>>>
          ("https://api.known.org.cn/api/v1/projects");

服务端实现要点

Web 宿主(如 KnownWeb)层:

  • 两条鉴权管道并行注册(AddAuthentication().AddCookie().AddJwtBearer()), 路由前缀决定用哪条:/api/* 走 Cookie、/api/v1/* 走 Bearer。
  • 默认全暴露 是个易踩的缺口——Config.AddModule 扫到的 [WebApi] 会同时挂到两条管道。 发布前必须显式白名单:机器面接口带 [MachineEndpoint] 特性、只有这些挂到 /api/v1。
  • scope 中间件在 Bearer 认证之后跑,校验令牌 scope 与 endpoint 需求匹配,不足返 403。

前端集成

LocalService 或 UserInfoService 提供当前用户:

@inject IAuthProvider Auth
@implements IDisposable

@if (_user is null) { <Spin /> }
else if (!_user.IsSignedIn) { <SignInPrompt /> }
else { <p>欢迎 @_user.Name</p> }

@code {
    private UserInfo? _user;
    protected override async Task OnInitializedAsync()
    {
        var res = await Auth.CurrentAsync();
        if (res.Success) _user = res.Data;
        Auth.UserChanged += OnUserChanged;
    }
    private void OnUserChanged(UserInfo u) => InvokeAsync(() => { _user = u; StateHasChanged(); });
    public void Dispose() => Auth.UserChanged -= OnUserChanged;
}

常见坑

  • 为不同子域各造一套登录/身份 — 不要。全站共享同一份身份后端与 .known.org.cn Cookie 会话,SSO 靠域与共享 DataProtection 实现,别在一个 apex 下裂出多套账户体系。
  • CLI 用 Cookie 登录 — 不要。CLI 走 PAT/Bearer,Cookie 只给浏览器。
  • 在 /api/v1 里返回 Set-Cookie — 不要。机器面无会话;返回 401 后 CLI 自己带新令牌重试。
  • PAT 明文入库 — 绝对不要。只存哈希、只在签发时一次性可见。

相关

  • 完整决策与拓扑变更见 docs/deploy-topology.md §3 与 Website/docs/docs-site-design.md §1。
  • 双鉴权的完整落地(令牌签发、scope 治理、授权服务器)依具体产品形态而定;本指南只描述开源侧可见的对外契约。
微信公众号二维码 扫码关注公众号
QQ 交流群二维码 扫码加入 QQ 群