Использование ASP.NET Ajax для вызова WCF через SSL - PullRequest
0 голосов
/ 23 января 2009

Я звоню в WCF со страницы ASP.NET, используя ASP.NET Ajax. Я использую проверку подлинности с помощью форм для защиты веб-сайта.

В процессе разработки все работало, как ожидалось, пока оно не было развернуто на производственном сервере, после чего я начал получать ошибки JavaScript, поскольку служба не может быть найдена. Рабочий сервер использует SSL, поэтому я добавил следующее в мой web.config :

<webHttpBinding>
    <binding name="webBinding">
    <security mode="Transport" />
    </binding>
</webHttpBinding>

Это предотвратило возникновение ошибок JavaScript, но теперь служба WCF ведет себя не так, как раньше.

Перед настройкой безопасности для передачи вызова службы WCF из ASP.NET Ajax должен выполнить Application_AuthenticateRequest в моем Global.asax. Это настроит пользовательский IPrinciple на HttpContext.Current.User на основе билета проверки подлинности с помощью форм. Конструктор для моей службы WCF устанавливает Thread.CurrentPrinciple = HttpContext.Current.User, поэтому моя служба имеет доступ к IPrinciple, установленному во время Application_AuthenticateRequest.

После изменения безопасности на Transport, похоже, он не запускается через Application_AuthenticateRequest, потому что мой Thread.CurrentPrinciple не мой пользовательский IPrinciple.

Кто-нибудь знает, как я могу получить такое же поведение, как до использования транспорта, так и после использования транспорта?

Моя веб-страница использует следующие ссылки на службу WCF:

<asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="
    <Services>
        <asp:ServiceReference Path="~/Services/MyService.svc" />
    </Services>
</asp:ScriptManagerProxy>

Код, используемый в моем Application_AuthenticateRequest:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    String cookieName = FormsAuthentication.FormsCookieName;
    HttpCookie authCookie = Context.Request.Cookies[cookieName];

    if (authCookie == null)
    {
        return;
    }

    FormsAuthenticationTicket authTicket = null;
    try
    {
        authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    }
    catch
    {
        return;
    }

    if (authTicket == null)
    {
        return;
    }

    HttpContext.Current.User = new CustomPrinciple(authTicket.Name);
}

1 Ответ

1 голос
/ 10 февраля 2010

Простое изменение защиты с Нет на Транспорт не должно влиять на приложение, запущенное через Authenticate_Request. Возможно, вам следует присоединить отладчик к реализации сервиса и посмотреть, что такое HttpContext.Current.User. Это ваш пользовательский принципал или он тоже не установлен? Вы также можете добавить туда пару сообщений Debug.Write и посмотреть, каков порядок операций. Происходит ли событие Authenticate_Request после того, как вы ожидаете его?

Возможно, вы столкнулись с этой проблемой из MS Connect , если вы используете <serviceAuthorization principalPermissionMode="UseAspNetRoles" /> в своей конфигурации - похоже, этот параметр не совместим с защищенным транспортом, и WCF переопределяет принципала. Если вы устанавливаете принципал, похоже, вам нужно использовать principalPermissionMode="None" для этого.

Убедитесь, что у вас по-прежнему включен Режим совместимости ASP.NET в службе либо через config (<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />), либо через атрибуты службы ([AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]). Без этого у службы не будет доступа к HttpContext.Current.

Кроме того, вместо получения HttpContext.Current.User в конструкторе реализации службы, попробуйте переместить его в поведение, которое вы присоединяете к службе. Реализуйте IDispatchMessageInspector, который обрабатывает событие AfterReceiveRequest и передает принципала из веб-контекста в поток. Это будет выглядеть примерно так:

public class HttpContextPrincipalInspector : IDispatchMessageInspector
{
  public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
  {
    if (HttpContext.Current != null)
    {
      IPrincipal principal = HttpContext.Current.User;
      Thread.CurrentPrincipal = principal;
    }
    return null;
  }

  public void BeforeSendReply(ref Message reply, object correlationState) { }
}

И, конечно, реализовать IEndpointBehavior для подключения диспетчера ...

public class HttpContextPrincipalBehavior : IEndpointBehavior
{
  public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
  {
    ChannelDispatcher channelDispatcher = endpointDispatcher.ChannelDispatcher;
    foreach (EndpointDispatcher endpointDispatch in channelDispatcher.Endpoints)
    {
      endpointDispatch.DispatchRuntime.MessageInspectors.Add(new HttpContextPrincipalInspector());
    }
  }

  // AddBindingParameters, ApplyClientBehavior, and Validate implementations
  // can be empty - they don't do anything.
}

... и пользовательский BehaviorExtensionElement, чтобы вы могли использовать его в конфигурации WCF:

public class HttpContextPrincipalElement : BehaviorExtensionElement
{
  public override Type BehaviorType
  {
    get { return typeof(HttpContextPrincipalBehavior); }
  }

  protected override object CreateBehavior()
  {
    return new HttpContextPrincipalBehavior();
  }
}

Затем вы можете сконфигурировать любую из ваших служб, чтобы использовать это как поведение конечной точки, чтобы реализация службы напрямую не общалась с веб-контекстом. Это немного облегчает тестирование и может полностью решить проблему - каждый раз, когда приходит сообщение для службы, оно автоматически передает основную часть, а не полагается на создание службы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...