使用OpenIddict集成Microsoft外部登录时回调报invalid_client错误
问题描述
使用OpenIddict编写认证服务,支持本地账号和Microsoft账号生成令牌。在Azure上授权成功,但重定向到回调时,OpenIddict抛出invalid_client错误。相关配置及代码如下:
Startup.cs 配置
// Register the OpenIddict server components. .AddServer(options => { options //.AllowClientCredentialsFlow() .AllowAuthorizationCodeFlow() .RequireProofKeyForCodeExchange() .AllowRefreshTokenFlow()//.AllowImplicitFlow() .AllowPasswordFlow(); options .SetTokenEndpointUris("/connect/token") .SetAuthorizationEndpointUris("/connect/authorize") .SetIntrospectionEndpointUris("/connect/introspect"); options.AddEncryptionCertificate(config["Certificates:EncryptionCertificate"]); // Register the signing credentials. options.AddSigningCertificate(config["Certificates:SigningCertificate"]); // Register scopes (permissions) options.RegisterScopes("api"); options.SetAccessTokenLifetime(TimeSpan.FromMinutes(15)); options.SetRefreshTokenLifetime(TimeSpan.FromMinutes(60)); // Register the ASP.NET Core host and configure the ASP.NET Core-specific options. options .UseAspNetCore() .EnableTokenEndpointPassthrough() .EnableAuthorizationEndpointPassthrough(); }) .AddClient(options=> { options.AddDevelopmentEncryptionCertificate(); options.AddDevelopmentSigningCertificate(); options.AllowAuthorizationCodeFlow(); options.UseAspNetCore().EnableRedirectionEndpointPassthrough(); options.UseWebProviders() .AddMicrosoft(options=> { options.SetClientId("xxxxx"); options.SetClientSecret("xxxx"); options.SetRedirectUri("connect/callback/microsoft"); }); });
AccountController 挑战逻辑
[HttpGet] [AllowAnonymous] public IActionResult Login(string returnUrl = null, string provider="") { if (string.Equals(provider,"microsoft", StringComparison.OrdinalIgnoreCase)) { return new ChallengeResult(properties: null, authenticationSchemes: new[] { Providers.Microsoft }); } }
AuthorizationController 回调定义
[HttpGet("~/callback/github")] [HttpPost("~/callback/github")] [AllowAnonymous] public async Task<IActionResult> CallBackGitHub(CancellationToken cancellationToken) { // 回调逻辑 }
疑问:在Azure应用注册页面找不到添加client_id的入口,请问如何传递OpenIddict中已配置的client_id?或者是否可以在执行回调函数时跳过client_id检查?
解决方案
1. 修正回调端点不匹配问题
你配置的Microsoft回调URI是connect/callback/microsoft,但实际定义的回调方法是针对GitHub的~/callback/github,这会导致回调请求无法正确匹配处理方法,直接修改回调方法的路由为对应Microsoft的路径:
[HttpGet("~/connect/callback/microsoft")] [HttpPost("~/connect/callback/microsoft")] [AllowAnonymous] public async Task<IActionResult> CallBackMicrosoft(CancellationToken cancellationToken) { // 处理Microsoft回调逻辑 var result = await HttpContext.AuthenticateAsync(OpenIddictClientAspNetCoreDefaults.AuthenticationScheme); // 后续生成令牌等操作 }
2. 正确传递client_id到授权流程
发起Microsoft登录挑战时,需要将OpenIddict的客户端ID等信息通过AuthenticationProperties传递,而不是传入null。修改Login方法:
[HttpGet] [AllowAnonymous] public IActionResult Login(string returnUrl = null, string provider = "") { if (string.Equals(provider, "microsoft", StringComparison.OrdinalIgnoreCase)) { var properties = new AuthenticationProperties { RedirectUri = Url.Action(nameof(CallBackMicrosoft)), Items = { ["OpenIddict.Client:ClientId"] = "xxxxx", // 这里填你在OpenIddict Client中配置的ClientId ["OpenIddict.Client:Scope"] = "api", ["OpenIddict.Client:ReturnUri"] = returnUrl } }; return new ChallengeResult(Providers.Microsoft, properties); } // 本地账号登录逻辑 }
3. Azure应用注册的ClientId说明
Azure应用注册的应用程序(客户端)ID就是你在OpenIddict中配置的SetClientId("xxxxx")的值,这个ID在Azure应用注册的"概述"页面就能找到,不需要额外添加,只要确保OpenIddict配置的ClientId和Azure上的完全一致即可。
4. 关于跳过client_id检查
不建议跳过client_id检查,这会严重破坏认证流程的安全性,导致恶意客户端可以冒充合法客户端获取令牌。如果确实有特殊需求,需要通过自定义OpenIddict的验证逻辑实现,但强烈不推荐这么做。
内容的提问来源于stack exchange,提问作者Binki
相关产品推荐
相关产品推荐

