Аутентификация веб-приложения ASP.NET с помощью службы WCF

Фон

У меня есть веб-приложение ASP.NET, которое взаимодействует с службами WCF. Веб-приложение и службы WCF находятся под моим контролем. В веб-приложении ASP.NET используется пользовательская реализация модели поставщика членства ASP.NET(с паролями, хранящимися в хешированной форме) для аутентификации пользователей, которые входят в веб-приложение. Как веб-приложение ASP.NET, так и службы WCF имеют доступ к одной и той же базе данных членства.

Поскольку пользователи будут предоставлять свой пароль только один раз, и я не хочу хранить их пароли в любом месте или раздражать их, повторно прося их пополнять свой пароль, мне нужен соответствующий механизм для аутентификации пользователей с помощью WCF услуги.

Основываясь на других вопросах и ответах, которые я видел, я рассматриваю подход "сеанса входа в систему", в котором пользовательский сеанс будет создан в базе данных пользовательского членства, когда пользователь первоначально войдет в веб-приложение, сеанс идентификации, идентифицированный GUID, и автоматически истекает после периода бездействия. GUID сеанса входа будет "запоминаться" веб-приложением для каждого зарегистрированного пользователя (либо сохраненного в билете проверки подлинности форм, либо в сеансе).

Служба WCF также предоставит свою собственную операцию входа в систему, принимающую имя пользователя и пароль и возвращающую GUID сеанса входа, как описано выше.

Служба WCF затем примет GUID сеанса входа для всех других операций и проверит, что GUID представляет действительный сеанс регистрации, который еще не истек, прежде чем разрешить операцию продолжить.

Я сделал довольно много фонового чтения на этом, и есть много материала о прямом использовании типа учетных данных клиента UserName, но для этого потребуется, чтобы веб-приложение запоминало пароль пользователя, что не кажется как отличная идея для меня.

Я провел некоторое исследование и нашел материал на MSDN, но это, похоже, требует больших усилий для реализации того, что (по крайней мере для меня) похоже на довольно распространенный сценарий использования.

Как создать пользовательский токен

Вопрос

Является ли общий подход "сеанса входа" описанным выше разумным?
Если да, то каков наилучший способ его достижения?
Если нет, можете ли вы предложить альтернативу?

Ответ 1

Спасибо всем за ваш вклад. Я остановился на подходе (по крайней мере пока). Это довольно просто и хорошо работает для моих целей.

Используя "ClientName" clientCredentialType и явный метод входа в службу, который возвращает токен безопасности (сведения о генерации маркера опущены для краткости), клиент службы может решить, передавать ли подлинный пароль в качестве свойства пароля на учетных данных клиента или вместо этого используется токен безопасности (полученный из метода входа). Если клиент является веб-приложением, токен безопасности может быть сохранен в билете проверки подлинности форм или сеансе или где-либо еще.

Используя "Пользовательский" userNamePasswordValidationMode и пользовательскую реализацию UserNamePasswordValidator, валидатор проверяет пароль, чтобы определить, является ли он действительным маркером безопасности или паролем - если это пароль, то учетные данные клиента аутентифицируются в хранилище пользователей (SQL Server база данных), и если это токен безопасности, то он проверяется, чтобы убедиться, что он действителен, не истек и принадлежит имени пользователя.

Ответ 2

Это очень разумный подход.

Для этого вы настраиваете конечную точку службы и настраиваете ее с помощью своего пользовательского поставщика членства (вы можете сделать то же самое с поставщиком членства в SQL, для него не требуется настраиваемый).

В веб-приложении вы настроили событие Authenticate для элемента управления Login, чтобы создать новый прокси-сервер службы и установить имя пользователя/пароль в ClientCredentials в прокси-сервере.

Теперь, когда вы выполняете вызов Сервиса через прокси-сервер, WCF передает эти учетные данные через безопасный канал в службу и использует их для аутентификации.

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

protected void LoginControl_Authenticate(object sender, AuthenticateEventArgs e)
{
    bool Authenticated = false;
    try
    {
        MyServiceClient proxy = new MyServiceClient("MyServiceEndpoint");
        proxy.ClientCredentials.UserName.UserName = LoginControl.UserName;
        proxy.ClientCredentials.UserName.Password = LoginControl.Password;

        //It doesn't really matter what is called or what it does because 
        //Membership Provider for the Service does the authentication.
        string retval = proxy.login("Logging in"); 

        //Now that channel is established the proxy needs to be kept
        //since it contains the channel state which includes a private key
        Session["MyServiceProxy"] = proxy;  
        Authenticated = true;
    }
    catch (Exception ex)
    {
        //Login Error...
    }
    e.Authenticated = Authenticated;
}

Ответ 3

Есть два возможных решения, о которых я могу думать:

Во-первых, если служба WCF является внутренней службой, веб-приложение может затем отправить имя пользователя, запрашивающего данные с каждым запросом.

Во-вторых, вы храните имя пользователя и хэш пароля (или фактического пароля) где-то. Либо в состоянии сеанса, либо в cookie пользователя (файл cookie, хранящийся в памяти, передается пользователю через https). Затем передайте имя пользователя и пароль службе WCF с каждым запросом.

Ответ 5

Я бы предложил взглянуть на Geneva, который направлен на решение таких сценариев, как ваш. Основная идея заключается в том, чтобы требовать один и тот же токен безопасности, как и HttpModule, как для служб WCF, так и для сайта ASP. Токен будет выпущен после аутентификации против вашей базы данных членства и может содержать полезную информацию (претензии) для пользователя.

Для вступления вы можете прочитать статью Bustamante.

Ответ 6

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

Код фактически встроен в фреймворк - вам просто нужно создать файл .svc для его использования.

http://msdn.microsoft.com/en-us/library/bb398990.aspx