OpenIdDict - 为 XHR 请求禁用 "connect/authorize" 上的重定向

OpenIdDict - Disable redirect on "connect/authorize" for XHR requests

我正在使用 openIdDict 的示例 MVC 应用程序来实现授权代码流。但是,我有一个 angular 6 应用程序,用于用户用于授权请求的登录页面。我已经让 angular 的所有东西都在工作,但是当我向 "connect/authorize" 提交请求时,它生成了一个 302。302 被浏览器捕获并且正在发生重定向,但我不想那。我希望请求以 200 的形式出现,然后 angular 应用程序可以从那里控制重定向。

我想这样做的原因: 1. 我正在集成的系统需要在重定向中填充额外的查询字符串参数(state * others)。我希望我的 angular 应用程序填充这些而不是 connect/authorize。 2. angular 应用程序将在用户允许授权之后但在重定向发生之前为用户提供额外的 instructions/information。

我的问题是: 1. 是否可以更改 openiddict 生成的响应代码? 2. 我是不是偏离了轨道,让这件事变得比应该做的更难了?

Startup.cs 配置

            services.AddOpenIddict()
            .AddCore(coreOptions =>
            {
                coreOptions.UseEntityFrameworkCore().UseDbContext<ApplicationDbContext>();
            })
            .AddServer(serverOptions =>
            {
                serverOptions.UseMvc();

                serverOptions.EnableAuthorizationEndpoint(oauthOptions.AuthorizePath)
                .EnableTokenEndpoint(oauthOptions.TokenPath)
                       .EnableLogoutEndpoint(oauthOptions.LogoutPath);

                serverOptions.AllowAuthorizationCodeFlow()
                       .AllowPasswordFlow()
                       .AllowRefreshTokenFlow();

                serverOptions.SetAccessTokenLifetime(new TimeSpan(0, oauthOptions.AccessTokenLifetimeMinutes, 0));
                serverOptions.SetRefreshTokenLifetime(new TimeSpan(0, oauthOptions.RefreshTokenLifetimeMinutes, 0));

                if (!oauthOptions.RequireSSL)
                {
                    serverOptions.DisableHttpsRequirement();
                }

            });

只有一种情况下 OpenIddict 会透明地执行此操作:当您明确启用请求缓存时:

services.AddOpenIddict()
    .AddCore(options =>
    {
        // ...
    })

    .AddServer(options =>
    {
        // ...
        options.EnableRequestCaching();
    });

启用后,此功能将授权请求存储在 IDistributedCache 中,并用单个 request_id 参数替换授权请求参数,该参数用于表示请求。为此,它确实使用了 302 重定向。

如果您不喜欢这种行为,请不要在 OpenIddict 服务器选项中调用 options.EnableRequestCaching()

我决定编写自己的中间件来拦截 Identity 生成的 302 请求,并将其替换为具有 JSON 正文的 200 请求。我确信这可以简化,也许我只是错过了一些重要的东西而且我偏离了轨道。底线是此解决方案允许某人使用 ajax.

实施授权代码流

Startup.cs

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        //put this before any other middleware runs
        app.UseMiddleware<AuthorizeRequestMiddleware>();
        ...
    }

AuthorizeRequestMiddleware

public class AuthorizeRequestMiddleware
{
    private readonly RequestDelegate _next;

    public AuthorizeRequestMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        context.Response.OnStarting(AuthorizeStartingHandler, state: context);

        // Let the middleware pipeline run
        await _next(context);
    }

    private Task AuthorizeStartingHandler(object context)
    {

        HttpContext httpContext = (HttpContext)context;
        if (httpContext.Request.Path.HasValue && httpContext.Request.Path.Value == "/connect/authorize")
        {
            httpContext.Response.StatusCode = (int)HttpStatusCode.OK;
            AuthorizationCodeResponse responseBody = new AuthorizationCodeResponse(httpContext.Response.Headers["Location"][0]);
            httpContext.Response.WriteAsync(JsonConvert.SerializeObject(responseBody));
        }

        return Task.CompletedTask;
    }
}

AuthorizationCodeResponse 这是我自己的class。您可以根据需要使响应看起来像。

public class AuthorizationCodeResponse
{
    public AuthorizationCodeResponse(string redirectUri)
    {
        this.RedirectUri = redirectUri;
    }

    public string RedirectUri { get; set; }
}