一套接口,接入 31 个第三方登录

CollectiveOAuth 是 .NET 平台的 OAuth 登录聚合库。生成授权地址、处理回调、换取用户信息,在每个平台上都是同样的两个调用。

  • 31 个平台
  • .NET Framework 4.6.2+、.NET Standard 2.0、.NET 8
  • 行为与 Java 版 JustAuth 逐项比对测试

安装

目前通过源码引用使用。克隆仓库后,在你的项目里引用类库项目:

bash
git clone https://github.com/geekoutnet/CollectiveOAuth.git
dotnet add 你的项目.csproj reference CollectiveOAuth/Come.CollectiveOAuth/Come.CollectiveOAuth.csproj

类库同时编译三个目标框架,引用时会自动选择匹配的版本:

你的项目使用的版本
ASP.NET Core / .NET 8 及以上net8.0
ASP.NET MVC 5 / .NET Framework 4.6.2 及以上net462
其他 .NET Standard 2.0 兼容项目netstandard2.0

快速开始

以 GitHub 登录为例。其他平台只是换一个请求类,用法完全相同。

  1. 在第三方平台创建应用 拿到 clientId、clientSecret,并把回调地址登记为你站点上的一个地址,例如 https://your.site/oauth2/callback/github。
  2. 注册 state 缓存 state 用来防止 CSRF:生成授权地址时写入缓存,回调时校验并删除。ASP.NET Core 中注册一次即可:
    C#
    // Program.cs
    builder.Services.AddDistributedMemoryCache();
    builder.Services.AddSingleton<IAuthStateCache, DistributedAuthStateCache>();
    .NET Framework 项目不需要这一步,默认使用进程内缓存。
  3. 跳转到授权页
    C#
    var config = new ClientConfig
    {
        clientId = "你的 Client ID",
        clientSecret = "你的 Client Secret",
        redirectUri = "https://your.site/oauth2/callback/github"
    };
    var request = new GithubAuthRequest(config, authStateCache);
    return Redirect(request.authorize(AuthStateUtils.createState()));
  4. 在回调里换取用户信息 第三方平台会带着 code 和 state 回到你的回调地址。把参数绑定到 AuthCallback,交给同一个请求类:
    C#
    public IActionResult Callback(AuthCallback callback)
    {
        var request = new GithubAuthRequest(config, authStateCache);
        AuthResponse response = request.login(callback);
        if (!response.ok())
        {
            return BadRequest(response.msg);   // 例如 "Illegal state [GITHUB]"
        }
        var user = (AuthUser)response.data;
        // user.uuid 是该平台下的唯一标识,user.token 里是 access_token 等令牌信息
        return Ok(user.nickname);
    }
仓库里的 Come.AspNetCore.Sample(.NET 8)和 Come.Web.Sample(MVC 5)是完整示例:按平台名创建请求类、从配置文件读取参数,访问 /OAuth2/Authorization?authSource=GITHUB 即可走通。

配置项

所有平台共用 ClientConfig。大多数平台只需要前三项,个别平台需要额外字段,见支持的平台。

字段说明
clientId平台分配的应用 ID(AppKey / AppID)。必填。
clientSecret应用密钥。必填。支付宝填应用私钥。
redirectUri回调地址,必须以 http:// 或 https:// 开头,并与平台后台登记的一致。
scopes自定义授权范围列表。不填时使用该平台的默认范围。
httpConfig超时(毫秒)与代理,见超时与代理。
ignoreCheckState为 true 时回调不校验 state。会失去 CSRF 防护,仅在确有需要时使用。
ignoreCheckRedirectUri为 true 时不校验回调地址格式。
pkce开启 PKCE 模式(支持该模式的平台)。
alipayPublicKey支付宝公钥。支付宝必填。
agentId企业微信应用 AgentId。企业微信扫码必填。
stackOverflowKeyStack Overflow 的 Key。该平台必填。
domainPrefix团队域名前缀。Coding 必填。
tenantId微软 Entra ID 租户,默认 common。
unionId设为 "true" 时,QQ 登录同时获取 unionid(需先在 QQ 互联申请权限)。

从配置文件读取

示例项目按 CollectiveOAuth_{平台名}_{字段} 的规则,从 AppSettings 节点读取配置:

appsettings.json
{
  "AppSettings": {
    "CollectiveOAuth_GITHUB_ClientId": "...",
    "CollectiveOAuth_GITHUB_ClientSecret": "...",
    "CollectiveOAuth_GITHUB_RedirectUri": "https://your.site/oauth2/callback?authSource=GITHUB"
  }
}

ASP.NET Core 中调用一次 AppSettingUtils.UseConfiguration(configuration) 后,环境变量和 appsettings.{环境}.json 也会生效。

密钥不要提交到代码仓库。生产环境请用环境变量或密钥管理服务注入。

支持的平台

选择一个平台,查看要用的请求类、额外配置和回调参数。

state 与缓存

authorize() 会把 state 写入缓存,login() 校验通过后立即删除。所以同一个回调地址只能使用一次,被截获的回调无法重放。

实现适用场景
DefaultAuthStateCache默认实现,进程内缓存,3 分钟过期。适合单机部署。
DistributedAuthStateCache基于 IDistributedCache。多台服务器部署时,回调可能落到另一台机器,必须使用它并接入 Redis 等共享缓存。
C#
// 多实例部署:换成 Redis(需要 Microsoft.Extensions.Caching.StackExchangeRedis)
builder.Services.AddStackExchangeRedisCache(o => o.Configuration = "localhost:6379");
builder.Services.AddSingleton<IAuthStateCache, DistributedAuthStateCache>();

也可以实现 IAuthStateCache 接口,接入你自己的存储。

超时与代理

默认超时为 3 秒,与 JustAuth 一致。访问海外平台较慢,或者需要走代理时,设置 httpConfig:

C#
config.httpConfig = new HttpConfig
{
    timeout = 15000,                                   // 毫秒,小于等于 0 表示不限制
    proxy = new WebProxy("http://127.0.0.1:7890")
};

第三方平台返回非 2xx 状态码时,login() 返回失败,msg 中带有状态码和响应内容的开头部分,便于排查。

返回结果与错误码

login()、refresh()、revoke() 都返回 AuthResponse:code 为 2000 表示成功,此时 data 是结果对象;否则 msg 说明原因。配置不全等问题会在创建请求类时直接抛出 AuthException,其中的 errorCode 与下表一致。

code含义常见原因
2000成功
5000失败第三方平台返回了错误,看 msg
5001未实现该平台没有刷新或撤销功能
5002参数不完整缺少 clientId、clientSecret 或平台必填的额外字段
5003不支持的操作平台没有提供对应的接口
5006回调地址不合法没有填写,或者不以 http/https 开头;支付宝不能使用 localhost
5008code 不合法回调里缺少授权码
5009state 不合法state 已使用、已过期(默认 3 分钟),或回调到了另一台没有共享缓存的服务器
5010缺少 refresh token
5011–5016令牌、kid、team id、client id/secret、企业微信 agentId 不合法

刷新与撤销授权

支持的平台见平台详情中的“刷新令牌”“撤销授权”两项。不支持时,调用会抛出 AuthException(5001 或 5003)。

C#
AuthResponse refreshed = request.refresh(user.token);
if (refreshed.ok())
{
    var token = (AuthToken)refreshed.data;
}

与 JustAuth 的差异

授权地址、发出的请求、解析出的用户信息,都与 Java 版 JustAuth 1.16.7 逐项比对测试过。以下几处是有意保留的不同:

  • state 校验通过后立即删除,防止回调被重放。JustAuth 不删除。
  • 授权地址中的参数默认做 URL 编码,回调地址带查询参数也不会出错。
  • 第三方返回非 2xx 时给出状态码和响应内容,不再吞掉错误。
  • 提供 DistributedAuthStateCache,支持多实例部署。
  • API 保持 C# 版原有命名:配置类叫 ClientConfig,部分平台名也不同,例如小米是 XIAOMI(JustAuth 为 MI)。

常见问题

回调总是返回 “Illegal state”

state 只能用一次,默认 3 分钟过期。刷新回调页面、授权页停留过久,或多台服务器没有共享缓存,都会出现这个错误。多实例部署请使用 DistributedAuthStateCache。

升级后访问海外平台超时

默认超时从旧版的 100 秒改成了 3 秒,与 JustAuth 一致。请通过 httpConfig.timeout 调大,或者配置代理。

创建请求类时抛出 AuthException

配置会在创建时校验。5002 表示缺少必填项,5006 表示回调地址不合法,对照配置项检查即可。

用户的性别是空的

平台没有返回性别时,gender 为 null,不会再默认显示为“女”。