У меня есть рабочий пользовательский UserNamePasswordValidator, который звонит в мой DB Oracle.
Этот класс происходит из Системы. IdentityModel. Селекторы. UserNamePasswordValidator и Проверение () метод возвращаются пусто.
Я загружаю свой Пользовательский объект из базы данных, и после того как пароль проверен, я хочу спрятать свой "Пользовательский" объект, таким образом, сервис может получить доступ к нему при движении о его бизнесе. В ASP.NET / земля Java я спрятал бы его в сессию или возможно мой полный Класс контроллера. Как я делаю это от Блока проверки допустимости в WCF?
Или, другими словами, какова лучшая практика на земле WCF для установки пользовательского Пользовательского объекта области для сервиса.
Обновление: Это - то, как я работал вокруг этого. Я кэширую Пользовательский объект во время блока проверки допустимости, затем получаю доступ к нему позже на шаге 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
для выполнения фактической авторизации . Таким образом, в политике авторизации вы установите свой пользовательский принципал в текущем потоке.
Чтобы иметь возможность пересылать информацию из проверки имени пользователя / пароля, вы можете реализовать аутентификатор маркера безопасности, который наследуется от UserNameSecurityTokenAuthenticator
. SecurityTokenAuthenticator сначала вызовет валидатор, и, если проверка завершится успешно, он может добавить вашу настраиваемую политику авторизации и отправить информацию о пользователе в политику через конструктор. Что-то вроде длинных строк этого:
public class CustomUsernameSecurityTokenAuthenticator : UserNameSecurityTokenAuthenticator
{
protected override bool CanValidateTokenCore(System.IdentityModel.Tokens.SecurityToken token)
{
return (token is UserNameSecurityToken);
}
protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateTokenCore(SecurityToken token)
{
var authorizationPolicies = new List<IAuthorizationPolicy>();
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();
}
}
Здесь есть статья, которая описывает немного больше о задействованных классах; http://blogs.msdn.com/card/archive/2007/10/04/how-identity-providers-can-show-custom-error-messages-in-cardspace.aspx
У меня точно такая же проблема.
Я использую API для подключения к моей базовой базе данных Oracle, и я "проверяю" данные входа в систему, открывая соединение.
Затем я хочу где-то сохранить это соединение (достаточно просто, я создам пул соединений для всех различных пользователей), но также создать пользовательскую идентификацию и принцип, представляющие этого пользователя, чтобы, когда он доберется до моей пользовательской политики IAuthorizationPolicy, ему не нужно было заново загружать эту информацию.
Я много искал и ничего не нашел, поэтому я планирую сделать следующее:
Проверить данные для входа в систему в пользовательском UserNamePasswordValidator, открыв API соединение.
Хранить открытое соединение в пуле соединений под именем пользователя.
Когда вызывается моя пользовательская IAuthorizationPolicy.Evaluate(), я посмотрю на предоставленную общую идентификацию:
IIdentity GetClientIdentity(EvaluationContext evaluationContext)
{
объект obj;
if (!evaluationContext.Properties.TryGetValue("Identities", out obj))
throw new Exception("Identity found");
IList identities = obj as IList;
if (identities == null || identities.Count <= 0)
throw new Exception("Identity found");
return identities[0];
}
(извините, что не могу избавиться от этой плохой HTML-эскейпинга)
Затем я беру соединение из пула на основе IIdentity.Name, использую это соединение для загрузки пользовательских данных из базы данных и храню их в пользовательском Identity и Principal, которые я устанавливаю в EvaluationContext:
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
IIdentity identity = GetClientIdentity(evaluationContext);
if (identity == null)
throw new Exception();
// Это мои пользовательские классы Identity и Principal
Identity customIdentity = new Identity();
Principal customPrincipal = new Principal(customIdentity);
// заполняем идентификатор и принципала по мере необходимости
evaluationContext.Properties["Principal"] = customPrincipal;
return true;
}
Тогда я должен иметь доступ к моим пользовательским идентификатору и принципалу, когда мне это нужно, используя System.Threading.Thread.CurrentPrincipal или CurrentIdentity.
Надеюсь, это в какой-то мере поможет; я не уверен, что это лучший способ, но это лучшее, что я придумал на данный момент...
Стив