如何在ASP.NET Core 2中配置Steam的OpenID Connect认证?
首先得明确一个核心问题:你用的AddOpenIdConnect中间件是为OpenID Connect (OIDC)协议设计的,但Steam采用的是旧版的OpenID 2.0标准,两者并不兼容——这就是为什么你会收到XRDS XML却无法解析、配置失效的原因。
下面给你两种可行的解决方案,优先推荐第一种,更简单可靠:
方案一:使用专门的Steam认证第三方中间件
社区维护的AspNet.Security.OpenId.Steam库完美适配Steam的OpenID 2.0流程,省去手动处理的麻烦:
安装NuGet包
用.NET CLI执行:dotnet add package AspNet.Security.OpenId.Steam或者在Visual Studio中通过NuGet包管理器搜索安装。
配置认证服务
修改ConfigureServices方法,替换原来的AddOpenIdConnect为AddSteam:public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); // 配置Steam认证 services.AddAuthentication() .AddSteam(steamOptions => { steamOptions.ApplicationKey = "<你的Steam API Key>"; // 替换为你的Steam API密钥 steamOptions.CallbackPath = "/auth/openid/return"; // 回调路径,和你之前的设置一致 steamOptions.Realm = "http://localhost:4000/"; // 你的站点域名 }); }确保认证中间件生效
在Configure方法中,要保证UseAuthentication在UseMvc之前调用:public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // 其他中间件(比如异常处理、静态文件)... app.UseAuthentication(); // 必须在UseMvc之前 app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }允许匿名访问回调路径
如果你的Identity配置了全局授权,需要在回调Action上添加[AllowAnonymous]属性,避免被拦截:[AllowAnonymous] public async Task<IActionResult> Return() { // 中间件会自动处理认证流程,你可以在这里获取用户信息 var result = await HttpContext.AuthenticateAsync(SteamAuthenticationDefaults.AuthenticationScheme); if (result.Succeeded) { // 从Claims中提取SteamID等信息 var steamId = result.Principal.FindFirst(ClaimTypes.NameIdentifier)?.Value; // 后续逻辑:创建/关联本地用户、登录等 } return RedirectToAction("Index", "Home"); }
方案二:手动处理OpenID 2.0流程(适合理解原理)
如果你不想依赖第三方库,可以手动实现OpenID 2.0的认证流程:
构造认证跳转链接
在登录Action中,生成Steam的认证URL并跳转:public IActionResult LoginWithSteam() { var returnUrl = Url.Action("Return", "Auth", null, Request.Scheme); var steamAuthUrl = "https://steamcommunity.com/openid/login" + $"?openid.ns=http://specs.openid.net/auth/2.0" + $"&openid.mode=checkid_setup" + $"&openid.return_to={Uri.EscapeDataString(returnUrl)}" + $"&openid.realm={Uri.EscapeDataString(Request.Scheme + "://" + Request.Host)}" + $"&openid.identity=http://specs.openid.net/auth/2.0/identifier_select" + $"&openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select"; return Redirect(steamAuthUrl); }处理回调并验证断言
在回调Action中,接收Steam返回的参数,然后发送POST请求到Steam的验证端点:[AllowAnonymous] public async Task<IActionResult> Return() { var form = Request.Query.ToDictionary(kv => kv.Key, kv => kv.Value.ToString()); form["openid.mode"] = "check_authentication"; using var client = new HttpClient(); var response = await client.PostAsync("https://steamcommunity.com/openid/login", new FormUrlEncodedContent(form)); var responseContent = await response.Content.ReadAsStringAsync(); // 验证返回内容是否包含"is_valid:true" if (responseContent.Contains("is_valid:true")) { // 提取SteamID:从openid.claimed_id中获取,格式为http://steamcommunity.com/openid/id/<SteamID64> var claimedId = Request.Query["openid.claimed_id"].ToString(); var steamId = claimedId.Split('/').Last(); // 后续逻辑:用Steam API获取用户信息、创建本地用户、登录等 } return RedirectToAction("Index", "Home"); }
为什么你的原配置失效?
AddOpenIdConnect中间件会自动请求OIDC标准的发现文档(通常是/.well-known/openid-configuration的JSON文件),但Steam返回的是OpenID 2.0的XRDS XML格式发现文档,中间件无法识别这种格式,自然无法完成认证流程。
内容的提问来源于stack exchange,提问作者Ryan Battistone

