WCF Custom Validator: как инициализировать объект «Пользователь» из пользовательского валидатора

У меня есть рабочий пользовательский UserNamePasswordValidator, который вызывает мою базу данных Oracle.

Этот class происходит от System.IdentityModel.Selectors.UserNamePasswordValidator и метод Validate () возвращает void.

Я загружаю свой объект User из базы данных, и как только пароль будет проверен, я хочу зачеркнуть мой объект «Пользователь», чтобы служба могла получить к нему доступ при работе с ней. В среде ASP.NET / Java я бы поставил его в сеанс или, возможно, в мой общий class controllerа. Как это сделать с помощью Validator в WCF?

Или, другими словами, какова наилучшая практика на земле WCF для установки пользовательского объекта домена для службы.

Обновление: вот как я работал над этим. Я кэширую объект User во время проверки, затем обращаюсь к нему позже на этапе AuthorizatinPolicy.

// this gets called after the custom authentication step where we loaded the User public bool Evaluate(EvaluationContext evaluationContext, ref object state) { // get the authenticated client identity IIdentity client = GetClientIdentity(evaluationContext); User user; OraclePasswordValidator.users.TryGetValue(client.Name, out user); if(user != null) { // set the custom principal evaluationContext.Properties["Principal"] = user; return true; } return false; } 

Я не эксперт WCF, но из того, что я читал и реализовал до сих пор, «правильным» способом сделать это было бы использование Validator для аутентификации пользователя, а затем реализация IAuthorizationPolicy для фактической авторизации . Таким образом, в политике авторизации вы установите свой пользовательский принцип в текущем streamе.

Чтобы иметь возможность пересылать информацию из проверки имени пользователя и пароля, вы можете реализовать аутентификатор токена безопасности, который наследуется от UserNameSecurityTokenAuthenticator . SecurityTokenAuthenticator сначала вызовет валидатор, и если проверка будет успешной, она может добавить вашу собственную политику авторизации и отправить userinfo в политику через конструктор. Что-то длинное:

 public class CustomUsernameSecurityTokenAuthenticator : UserNameSecurityTokenAuthenticator { protected override bool CanValidateTokenCore(System.IdentityModel.Tokens.SecurityToken token) { return (token is UserNameSecurityToken); } protected override ReadOnlyCollection ValidateTokenCore(SecurityToken token) { var authorizationPolicies = new List(); try { var userNameToken = token as UserNameSecurityToken; new CustomUserNameValidator().Validate(userNameToken.UserName, userNameToken.Password); var claims = new DefaultClaimSet(ClaimSet.System, new Claim(ClaimTypes.Name, userNameToken.UserName, Rights.PossessProperty)); authorizationPolicies.Add(new CustomAuthorizationPolicy(claims)); } catch (Exception) { authorizationPolicies.Add(new InvalidAuthorizationPolicy()); throw; } return authorizationPolicies.AsReadOnly(); } } 

Здесь есть статья, которая описывает немного больше вокруг задействованных classов; http://blogs.msdn.com/card/archive/2007/10/04/how-identity-providers-can-show-custom-error-messages-in-cardspace.aspx

У меня точно такая же проблема.

Я использую API для подключения к моей базовой базе данных Oracle и «проверю» данные входа в систему, открыв соединение.

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

Я много искал и ничего не нашел, поэтому я планирую сделать это:

  1. Подтвердите регистрационные данные в пользовательском UserNamePasswordValidator, открыв соединение API.

  2. Храните открытое соединение в пуле подключений под именем пользователя.

  3. Когда вызывается мой пользовательский IAuthorizationPolicy.Evaluate (), я буду смотреть на общий идентификатор:

     IIdentity GetClientIdentity(EvaluationContext evaluationContext) { object obj; if (!evaluationContext.Properties.TryGetValue("Identities", out obj)) throw new Exception("No Identity found"); IList identities = obj as IList; if (identities == null || identities.Count <= 0) throw new Exception("No Identity found"); return identities[0]; } 

(извините, я не могу избавиться от этого плохого HTML-экранирования)

  1. Затем я получаю соединение из пула на основе имени IIdentity.Name, используя это соединение для загрузки пользовательских данных из базы данных и сохранения их в пользовательской Identity and Principal, которую я установил в EvaluationContext:

     public bool Evaluate(EvaluationContext evaluationContext, ref object state) { IIdentity identity = GetClientIdentity(evaluationContext); if (identity == null) throw new Exception(); // These are my custom Identity and Principal classes Identity customIdentity = new Identity(); Principal customPrincipal = new Principal(customIdentity); // populate identity and principal as required evaluationContext.Properties["Principal"] = customPrincipal; return true; } 

Тогда я должен иметь доступ к моей персонализированной личности и принципалу всякий раз, когда мне это нужно, используя System.Threading.Thread.CurrentPrincipal или CurrentIdentity.

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

Стив