微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

例外:oauth 状态丢失或无效 ASP.NET Core 外部标识符 OAuth

如何解决例外:oauth 状态丢失或无效 ASP.NET Core 外部标识符 OAuth

我正在尝试在 Asp.Net Core (https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers) 中实现外部 OAuth。我的应用程序 (GitLab) 具有回调 URL https://myhost.com/signin-gitlab(中间件认使用)。

如果我运行下面的代码,我会得到“异常:oauth 状态丢失或无效。”但是,如果我从 Startup.cs 中删除“options.UserinformationEndpoint”,那么我将使用代码和状态参数重定向到 myhost.com/signin-gitlab,中间件应将这些参数交换为访问令牌。我的问题是,为什么我的状态参数被损坏(使用 UserinformationEndpoint)?为什么我没有获得访问令牌?我在这里错过了什么?

我的创业班:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using AspNet.Security.OAuth.GitLab;
using System.Net.Http;
using System.Net.Http.Headers;

namespace MyApp
{
    public class Startup
    {
        private readonly IConfiguration _cfg;

        public Startup(IConfiguration configuration) => _cfg = configuration;

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRouting();

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                    .AddCookie()
                    .AddGitLab("Gitlab",options => {
                        options.ClientId = "...";
                        options.ClientSecret = "...";

                        options.AuthorizationEndpoint = "https://mygitlabserver.com/oauth/authorize";
                        options.TokenEndpoint = "https://mygitlabserver.com/oauth/token";
                        options.Scope.Clear();
                        options.Scope.Add("api");
                        options.Savetokens = true;

                        options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                        options.UserinformationEndpoint = "https://mygitlabserver.com/api/v4/user"; 
                    });

            services.AddMvc();

        }

        public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
        {
            app.UseDeveloperExceptionPage();
            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();
               
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
            });
        }
    }
}

我的控制器:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;

namespace MyApp.Controllers
{
    public class HomeController : Controller
    {
        [HttpGet("/")]
        public IActionResult Index()
        {
            return View();
        }

        [HttpGet("/login")]
        public IActionResult LogIn()
        {
            // Instruct the middleware corresponding to the requested external identity
            // provider to redirect the user agent to its own authorization endpoint.
            // Note: the authenticationScheme parameter must match the value configured in Startup.cs
            return Challenge(new AuthenticationProperties { RedirectUri = "https://myhost.com/signin-gitlab" },"Gitlab");
        }   
    }
}

解决方法

首先,ASP.NET 外部身份提供者/社交登录要么使用身份框架,要么不使用身份框架。如果没有 Identity,它应该像这样设置 (https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/social-without-identity?view=aspnetcore-5.0):

public void ConfigureServices(IServiceCollection services)
{
    // requires
    // using Microsoft.AspNetCore.Authentication.Cookies;
    // using Microsoft.AspNetCore.Authentication.Google;
    // NuGet package Microsoft.AspNetCore.Authentication.Google
    services
        .AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddGoogle(options =>
        {
            options.ClientId = Configuration["Authentication:Google:ClientId"];
            options.ClientSecret = Configuration["Authentication:Google:ClientSecret"];
        });

    services.AddRazorPages();
}

第二个问题是在控制器内部:

return Challenge(new AuthenticationProperties { RedirectUri = "https://myhost.com/signin-gitlab" },"Gitlab");

就像在 aspnet-contrib 团队 (https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/blob/dev/samples/Mvc.Client/Controllers/AuthenticationController.cs) 的 MVC 示例应用程序中一样,它实际上应该是:

return Challenge(new AuthenticationProperties { RedirectUri = "/" },"Gitlab");

用户实际上正在接受身份验证,问题是他们随后被重定向到 OAuth 中间件的内部路由 /signin-gitlab,没有状态或代码参数,而不是主路由/索引操作,因此出现错误。

换句话说,我搞混了:

  • RedirectUri(身份验证后重定向用户的位置)
  • 回调 URL(OAuth 应用程序将带有状态和代码的用户重定向到 OAuth 中间件内部路由,默认情况下为 /signin-gitlab、/signin-google、/signin-facebook,但也可以使用选项覆盖.CallbackPath)。

也许我的困惑是由于回调 url 在 GitLab 文档 (https://docs.gitlab.com/ee/api/oauth2.html) 中被称为 REDIRECT_URI 造成的。

感谢 Nan Yu (https://stackoverflow.com/a/61452853/2768479) 和 Tratcher (https://github.com/dotnet/aspnetcore/issues/22125,https://github.com/aspnet/Security/issues/1756) 的启发性帖子。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。