OIDC+Identity Server 4环境下AuthenticateAsync的Scheme参数取值疑问
OIDC结合IdentityServer4对接Okta认证的Scheme疑问
我在用OIDC结合IdentityServer4对接Okta做认证,回调方法里调用了var result = await HttpContext.AuthenticateAsync("Identity.External");。一开始选Identity.External当Scheme是因为回调请求里的Cookie叫这个名,但后来在Startup.ConfigureServices()里改了Cookie名称后,这个调用还是正常工作,说明Scheme名称和Cookie名没关系。
由此产生几个疑问:
- 怎么确定
AuthenticateAsync()里该传的Scheme字符串值?有没有可接受的取值列表? - 传错Scheme时返回的已注册Scheme列表(比如Identity.Application、Identity.External这些)是不是都是默认注册的?有没有相关文档说明?
- 调试发现
DefaultAuthenticateScheme默认值是Identity.Application,但AuthenticateAsync必须传DefaultSignInScheme对应的Identity.External才有效,这和微软文档描述不符,原因是什么? - Duende的示例里用
IdentityServerConstants.ExternalCookieAuthenticationScheme作为SignInScheme和AuthenticateAsync的参数,同样和微软文档冲突,该怎么理解?
我的Startup.ConfigureServices()代码如下:
services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; // "Cookies" options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; options.DefaultSignOutScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) .AddOpenIdConnect("oidc", "OpenIdConnect", options => { options.Authority = "oktaUrlHere"; options.ClientId = "clientIdHere"; options.ClientSecret = "clientSecretHere"; options.SaveTokens = true; options.ResponseType = "code"; options.Scope.Add("groups"); options.Scope.Add("email"); options.Events = new CustomOpenIdConnectEvents { ... }; });
问题解答
1. 确定AuthenticateAsync()的Scheme值
Scheme值是你在注册认证服务时自定义指定的名称,或者框架提供的默认常量:
- 如果你用
AddCookie("MyCustomCookie"),那Scheme就是"MyCustomCookie"; - 框架自带的常量比如
CookieAuthenticationDefaults.AuthenticationScheme(对应"Cookies")、OpenIdConnectDefaults.AuthenticationScheme(对应"OpenIdConnect"),还有IdentityServer4里的IdentityServerConstants.ExternalCookieAuthenticationScheme(对应"Identity.External"); - 没有固定的可接受值列表,所有你通过
AddXXX系列方法注册的Scheme都可以用,比如你代码里的"oidc"也是一个合法的Scheme。
2. 默认注册的Scheme列表
那些默认的Scheme(Identity.Application、Identity.External等)是ASP.NET Core Identity默认注册的,当你调用AddIdentity或AddDefaultIdentity时,框架会自动注册这几个Cookie Scheme:
Identity.Application:存储本地用户的认证会话;Identity.External:存储第三方登录后的临时认证信息;Identity.TwoFactorRememberMe、Identity.TwoFactorUserId:用于双因素认证相关场景;- 这些默认注册逻辑在ASP.NET Core Identity的源码里有体现,官方文档会在Identity的认证配置章节提及。
3. DefaultAuthenticateScheme和Identity.External的矛盾点
你遇到的情况是因为第三方登录的流程特殊性:
- 当你通过Okta这类第三方身份提供商登录时,OIDC中间件会先把第三方返回的用户信息存在
Identity.External对应的Cookie里(这是IdentityServer4/ASP.NET Core Identity处理外部登录的默认行为); - 回调方法里需要先从这个临时Cookie里获取用户信息,再转换为本地的
Identity.Application会话; - 微软文档里说的
DefaultAuthenticateScheme是用于常规请求的默认认证Scheme,而外部登录回调是特殊场景,需要指定存储临时外部用户信息的Scheme,所以必须传Identity.External才能拿到正确的认证结果。
4. Duende示例中IdentityServerConstants.ExternalCookieAuthenticationScheme的使用
IdentityServerConstants.ExternalCookieAuthenticationScheme其实就是"Identity.External"的常量别名,和你之前用的字符串是同一个东西:
- Duende作为IdentityServer4的后续版本,沿用了这套Scheme命名规则;
- 之所以看起来和微软文档冲突,是因为微软文档讲的是通用ASP.NET Core认证,而IdentityServer/Duende在外部登录流程上有自己的约定:用专门的外部Cookie存储第三方登录的临时信息,所以回调时必须指定这个Scheme;
- 本质上和ASP.NET Core Identity的外部登录逻辑一致,只是用了框架提供的常量来代替硬编码字符串,更规范。
内容的提问来源于stack exchange,提问作者David Klempfner
相关产品推荐
相关产品推荐

