Как передать имя пользователя WCF clientCredentialType в другую службу?

У меня есть несколько служб WCF, размещенных в IIS6 (не должно влиять на эту проблему) на одном хосте, и я хочу, для производительности/обслуживания и по другим причинам, объединить несколько запросов в 1 запрос с использованием фасадной службы. Все делается с помощью специального контракта на обслуживание/ Служба с операцией, вызывающей другие службы для выполнения нескольких операций.

Я использую WSHTTP (вероятно, BasicHttp в ближайшем будущем) с безопасностью сообщений и типом учетных данных клиента UserName.

Я хочу, чтобы Facade Service использовал учетные данные клиента. Это означает, что вызов внутренней службы получит учетные данные, как если бы клиент вызывал ее напрямую.

Например: Клиент вызывает FacadeService.CompositeOperation с именем пользователя «A» и паролем «B». Теперь FacadeService.CompositeOperation необходимо вызвать BackEndService.BackendOperation, установив для Credentials.UserName.UserName значение «A» и Credentials.UserName.Password для «B», точно так же, как это сделал клиент при вызове этой операции. У меня нет возможности извлечь эту информацию в WCF (и это должно быть, потому что это конфиденциальная информация), но я не нашел способа взять «токен» из них и передать его серверной службе (мне не нужно знать эту информацию в FacadeService, только чтобы передать их).

В FacadeService, как и в BackEndService, аутентификация выполняется через поставщика ASP.NET, авторизация представляет собой настраиваемую авторизацию на основе ролей, берущую имя пользователя из PrimaryIdentity, поэтому для PrimaryIdentity в BackEndService должно быть установлено то, что отправляет клиент.

Как я должен это делать?


person Community    schedule 21.04.2009    source источник


Ответы (2)


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

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

  • Вы не можете совершать вызовы других служб из кода на стороне сервера из метода, который вы нажимаете? Как и раньше, вы находитесь на стороне сервера, контекст безопасности должен содержать идентификатор пользователя, которого вы ищете, поэтому вызовы других служб будут использовать тот же идентификатор.

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

Надеюсь, что это поможет - удачи!

person Tanner    schedule 22.04.2009
comment
Привет, спасибо за ответ. 1. На данный момент проблем с производительностью нет, но в будущем буду тестировать, если и буду менять, то использовать привязки TCP/IPC. Что касается ясности кода, то здесь нет никаких проблем, так как эта фасадная услуга разработана и сделана для этой цели. 2. Это невозможно, потому что я использую учетные данные UserName и для этого требуется имя пользователя/пароль. 3. Олицетворение работает только для Windows, и мне нужен тип учетных данных имени пользователя/пароля. Спасибо. - person ; 22.04.2009

Однажды я попытался сохранить пароль вместе с именем пользователя в PrimaryIdentity. Чтобы достичь этого, нам нужно предоставить новый UserNameSecurityTokenAuthenticator, который будет аутентифицировать имя пользователя и пароль, а затем может сохранить его в Identity, а затем он сохранит Identity в SecurityContext WCF.

Шаги, чтобы сделать

Классы

1.) Тестсервисхост: сервисхост

2.) UserNamePasswordSecurityTokenManager : ServiceCredentialsSecurityTokenManager

3.) TestUserNameSecurityTokenAuthenticator: UserNameSecurityTokenAuthenticator

4.) MyIdentity : IIdentity

5.) MyAuthorizatoinPolicy : IAuthorizationPolicy

1.) Создайте новый класс ServiceHost TestServiceHost

2.) В TestServiceHost переопределить OnOpening и предоставить новый класс UserNamePasswordServiceCredentials.

protected override void OnOpening()
{
    base.OnOpening();
    this.Description.Behaviors.Add(new UserNamePasswordServiceCredentials());
}

3.) Затем в UserNamePasswordServiceCredentials укажите новый UserNamePasswordSecurityTokenManager.

public override SecurityTokenManager CreateSecurityTokenManager()
{
    return new UserNamePasswordSecurityTokenManager(this);
}

4.) Затем в UserNamePasswordSecurityTokenManager укажите новый TestUserNameSecurityTokenAuthenticator.

public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            if (tokenRequirement.TokenType == SecurityTokenTypes.UserName)
            {
                outOfBandTokenResolver = null;
                return new TestUserNameSecurityTokenAuthenticator();
            }
            return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
        }

5.) Затем внутри TestUserNameSecurityTokenAuthenticator вы можете аутентифицировать имя пользователя и пароль и можете создать свою собственную личность. В этой функции вы вернете список политик IAuthorization для оценки. Я создал свою собственную Политику авторизации и передал ей свою новую личность, чтобы установить Идентификацию в контексте.

protected override System.Collections.ObjectModel.ReadOnlyCollection<System.IdentityModel.Policy.IAuthorizationPolicy> ValidateUserNamePasswordCore(string userName, string password)
        {           
            ClaimSet claimSet = new DefaultClaimSet(ClaimSet.System, new Claim(ClaimTypes.Name, userName, Rights.PossessProperty));
            List<IIdentity> identities = new List<IIdentity>(1);
            identities.Add(new MyIdentity(userName,password));
            List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
            policies.Add(new MyAuthorizationPolicy(ClaimSet.System, identities));
            return policies.AsReadOnly();
        }


public class MyAuthorizationPolicy : IAuthorizationPolicy
    {
        String id = Guid.NewGuid().ToString();
        ClaimSet issuer;
        private IList<IIdentity> identities;
        #region IAuthorizationPolicy Members


        public MyAuthorizationPolicy(ClaimSet issuer, IList<IIdentity> identities)
        {
            if (issuer == null)
                throw new ArgumentNullException("issuer");
            this.issuer = issuer;
            this.identities = identities;

        }

        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            if (this.identities != null)
            {
                object value;
                IList<IIdentity> contextIdentities;
                if (!evaluationContext.Properties.TryGetValue("Identities", out value))
                {
                    contextIdentities = new List<IIdentity>(this.identities.Count);
                    evaluationContext.Properties.Add("Identities", contextIdentities);
                }
                else
                {
                    contextIdentities = value as IList<IIdentity>;
                }
                foreach (IIdentity identity in this.identities)
                {
                    contextIdentities.Add(identity);
                }
            }
            return true;
        }

        public ClaimSet Issuer
        {
            get { return this.issuer; }
        }

        #endregion

        #region IAuthorizationComponent Members

        public string Id
        {
            get { return this.id; }
        }

        #endregion
    }

Итак, этот пример показывает, как вы можете переопределить безопасность в WCF:

Теперь в вашей проблеме:

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

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

Лично я бы выбрал подход 2, но он приведет к новым накладным расходам.

person Nitin Midha    schedule 16.03.2010