Подтвердить что ты не робот

Настройка redirect_uri в Identity Asp.Net

Я пытаюсь установить redirect_uri для входа в facebook с идентификатором Asp.Net. Однако метод GetExternalLogin REST в AccountController запускается только в том случае, если redirect_uri является "/". Если я добавлю что-нибудь еще, это не вызывает GetExternalLogin, браузер показывает только * error: invalid_request *.

Однако URL-адрес содержит перенаправленный параметр, как это должно быть, например. если я добавлю redirect_uri как http://localhost:25432/testing

URL-адрес ответа выглядит следующим образом:

http://localhost:25432/api/Account/ExternalLogin?provider=Facebook&response_type=token&client_id=self&redirect_uri=http%3A%2F%2Flocalhost%3A25432%2Ftesting&state=0NctHHGq_aiazEurHYbvJT8hDgl0GJ_GGSdFfq2z5SA1

и окно браузера показывает: error: invalid_request

Любая идея, почему это работает только при перенаправлении на '/', но не на другие URL-адреса?

Спасибо!

4b9b3361

Ответ 1

Проблема заключается в том, что GetExternalLogin зарегистрирован как OAuthOptions.AuthorizeEndpointPath, который использовался для app.UseOAuthBearerTokens(OAuthOptions). Эта конфигурация ставит проверку на аргументы конечной точки.

if (!Uri.TryCreate(authorizeRequest.RedirectUri, UriKind.Absolute, out validatingUri))
{
    // The redirection endpoint URI MUST be an absolute URI
}
else if (!String.IsNullOrEmpty(validatingUri.Fragment))
{
    // The endpoint URI MUST NOT include a fragment component.
}
else if (!Options.AllowInsecureHttp &&
                    String.Equals(validatingUri.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
{
    // The redirection endpoint SHOULD require the use of TLS
}

И вы должны передать "Авторизовать запрос конечной точки, отсутствующий требуемый параметр response_type" и "Авторизованный запрос конечной точки содержит неподдерживаемый параметр response_type"

Ответ 2

Для всех, кто может столкнуться с этой проблемой: проблема в том, что вы берете (копируете) ApplicationOAuthProvider.cs из шаблона SPA в Visual Studio и там, где этот код:

    public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
    {
        if (context.ClientId == _publicClientId)
        {
            var expectedRootUri = new Uri(context.Request.Uri, "/");

            if (expectedRootUri.AbsoluteUri == context.RedirectUri)
            {
                context.Validated();
            }
        }

        return Task.FromResult<object>(null);
    }

Это, очевидно, блокирует любой redirect_uri, который не похож на http://localhost/ или http://domain.com/, поэтому, например, http://domain.com/home не будет работать.

Теперь это ниже источник InvokeAuthorizeEndpointAsync в Катане, который выполняет всю работу, и вы можете видеть, что он вызывает любой пользовательский OAuthProvider, который может быть зарегистрирован для этого приложения MVC/Web API (эта регистрация обычно происходит в Startup.Auth.cs):

    private async Task<bool> InvokeAuthorizeEndpointAsync()
    {
        var authorizeRequest = new AuthorizeEndpointRequest(Request.Query);

        var clientContext = new OAuthValidateClientRedirectUriContext(
            Context,
            Options,
            authorizeRequest.ClientId,
            authorizeRequest.RedirectUri);

        if (!String.IsNullOrEmpty(authorizeRequest.RedirectUri))
        {
            bool acceptableUri = true;
            Uri validatingUri;
            if (!Uri.TryCreate(authorizeRequest.RedirectUri, UriKind.Absolute, out validatingUri))
            {
                // The redirection endpoint URI MUST be an absolute URI
                // http://tools.ietf.org/html/rfc6749#section-3.1.2
                acceptableUri = false;
            }
            else if (!String.IsNullOrEmpty(validatingUri.Fragment))
            {
                // The endpoint URI MUST NOT include a fragment component.
                // http://tools.ietf.org/html/rfc6749#section-3.1.2
                acceptableUri = false;
            }
            else if (!Options.AllowInsecureHttp &&
                String.Equals(validatingUri.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
            {
                // The redirection endpoint SHOULD require the use of TLS
                // http://tools.ietf.org/html/rfc6749#section-3.1.2.1
                acceptableUri = false;
            }
            if (!acceptableUri)
            {
                clientContext.SetError(Constants.Errors.InvalidRequest);
                return await SendErrorRedirectAsync(clientContext, clientContext);
            }
        }

        await Options.Provider.ValidateClientRedirectUri(clientContext);

        if (!clientContext.IsValidated)
        {
            _logger.WriteVerbose("Unable to validate client information");
            return await SendErrorRedirectAsync(clientContext, clientContext);
        }

        var validatingContext = new OAuthValidateAuthorizeRequestContext(
            Context,
            Options,
            authorizeRequest,
            clientContext);

        if (string.IsNullOrEmpty(authorizeRequest.ResponseType))
        {
            _logger.WriteVerbose("Authorize endpoint request missing required response_type parameter");
            validatingContext.SetError(Constants.Errors.InvalidRequest);
        }
        else if (!authorizeRequest.IsAuthorizationCodeGrantType &&
            !authorizeRequest.IsImplicitGrantType)
        {
            _logger.WriteVerbose("Authorize endpoint request contains unsupported response_type parameter");
            validatingContext.SetError(Constants.Errors.UnsupportedResponseType);
        }
        else
        {
            await Options.Provider.ValidateAuthorizeRequest(validatingContext);
        }

        if (!validatingContext.IsValidated)
        {
            // an invalid request is not processed further
            return await SendErrorRedirectAsync(clientContext, validatingContext);
        }

        _clientContext = clientContext;
        _authorizeEndpointRequest = authorizeRequest;

        var authorizeEndpointContext = new OAuthAuthorizeEndpointContext(Context, Options);

        await Options.Provider.AuthorizeEndpoint(authorizeEndpointContext);

        return authorizeEndpointContext.IsRequestCompleted;
    }

Это ключ:

        await Options.Provider.ValidateClientRedirectUri(clientContext);

Итак, ваше решение состоит в том, чтобы изменить способ выполнения ValidateClientRedirectUri валидации - реализация SPA по умолчанию, как вы можете видеть, очень наивна.

Там много ppl имеет проблемы с SPA главным образом потому, что ему не хватает какой-либо полезной информации, и я имею в виду как для ASP.NET Identity, так и для OWIN и в отношении того, что происходит в реализации KnockoutJS.

Я хочу, чтобы Microsoft предоставила более подробные документы для этих шаблонов, потому что любой, кто попытается сделать что-то более сложное, столкнется с проблемами.

Я потратил несколько часов на это, копаясь в исходном коде OWIN (Katana), думая, что это вышеперечисленная реализация блокирует мои URI перенаправления, но это не так, надеюсь, поможет и кому-то еще.

НТН

Ответ 3

Основываясь на других ответах, я изменил код проверки в ApplicationOAuthProvider.cs, чтобы убедиться, что перенаправление uri находится в одном домене, например:

public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
        {
            if (context.ClientId == _publicClientId)
            {
                Uri expectedRootUri = new Uri(context.Request.Uri, "/");

                if (context.RedirectUri.StartsWith(expectedRootUri.AbsoluteUri))
                {
                    context.Validated();
                }
            }

            return Task.FromResult<object>(null);
        }