Как передать WCF UserName clientCredentialType другому сервису? - PullRequest
1 голос
/ 21 апреля 2009

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

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

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

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

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

Как мне это сделать?

Ответы [ 2 ]

0 голосов
/ 16 марта 2010

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

шаги к выполнению

Классы

1.) TestServiceHost: ServiceHost

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 вы можете аутентифицировать UseraName и пароль и создать свою собственную личность. В этой функции вы вернете список политик 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
    }

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

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

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

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

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

0 голосов
/ 22 апреля 2009

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

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

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

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

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

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