2012-05-12 2 views
3

Я хочу, чтобы иметь возможность обнаруживать, когда пользователь подписывается на мое приложение с использованием пассивных переменных, поэтому я могу добавить их в свою базу данных, если это первый раз, когда я использую мое приложение. Прямо сейчас я подписываюсь на WSFederationAuthenticationModule.SignedIn, но я чувствую, что что-то упускаю. В основном я не уверен, что лучше всего подписаться на мероприятие, я получил его для работы внутри PostAuthenticateRequest, но его немного взломало. Какие-либо предложения?Какое место лучше всего обнаружить при вводе пользователя при использовании azure acs и mvc3?

этот код из global.asax

public override void Init() 
    { 

     base.Init(); 

     PostAuthenticateRequest += (s, e) => 
     { 
      try 
      { 
       FederatedAuthentication.WSFederationAuthenticationModule.SignedIn -= SignedIn; 
      } 
      finally 
      { 
       FederatedAuthentication.WSFederationAuthenticationModule.SignedIn += SignedIn; 
      } 

     }; 


    } 


    private void SignedIn(object sender, EventArgs e) 
    { 
     //do something 
    } 

EDIT:

На данный момент я собираюсь использовать переменную флаг, чтобы убедиться, что я только один раз подписаться SignedIn. Если у кого-то нет других предложений, то есть :) спасибо за помощь Сандрино. Вот что я сейчас имею в виду.

private static bool isFirstRequest = true; 

    public override void Init() 
    { 


     base.Init(); 

     PostAuthenticateRequest += (s, e) => { 
     if (isFirstRequest) 
     { 
      FederatedAuthentication 
       .WSFederationAuthenticationModule.SignedIn += SignedIn; 
      isFirstRequest = false; 
     } 

     }; 

    } 


    private void SignedIn(object sender, EventArgs e) 
    { 

     //do something 

    } 

EDIT: Чуть подробнее. Эта проблема возникает, если я использую эмулятор azure, вероятно, это происходит при развертывании, но я этого не пробовал. Я тестировал, если я просто не могу отлаживать, пытаясь записать в текстовый файл, и текстовый файл не был создан.

ответ

6

Почему вы подпишитесь на SignedIn Событие при каждом возникновении события PostAuthenticateRequest? Вы можете просто подписаться на него при запуске приложения (в Global.asax) и он будет поднят для каждого пользователя, подписанного в:

public class MvcApplication : System.Web.HttpApplication 
{ 
    ... 

    protected void Application_Start() 
    { 
     ... 

     FederatedAuthentication.ServiceConfigurationCreated += (s, e) => 
     { 
      FederatedAuthentication.WSFederationAuthenticationModule.SignedIn += new EventHandler(OnUserSignedIn); 
     }; 
    } 

    private void OnUserSignedIn(object sender, EventArgs e) 
    { 
     // Custom logic here. 
    } 
} 

SignedIn событие является лучшим способом, чтобы обнаружить признак пользователя перед тем, как приложение будет продолжено. Взгляните на следующую диаграмму. Перед перенаправлением назад на страницу, событие SignedIn поднимается, чтобы позволить вам обнаружить знак пользователя в:

Federated Authentication Module diagram

Ссылка: http://msdn.microsoft.com/en-us/library/ee517293.aspx

+0

Я попытался это сделать, но WsFederationAuthenticationModule имеет значение null при запуске приложения, но доступен внутри запроса postauthenticate.Я считаю, что моя веб-конфигурация верна, я не редактировал ее вручную, чтобы добавить wsfederationmodule, просто использовав ссылку на ссылку sts. –

+0

Я адаптировал образец кода, это правда, что WSFederationAuthenticationModule не сразу доступен, когда приложение запускается. –

+0

Это все еще не работает, WsFederationAuthenticationModule доступен в этом случае, но подписка на событие signedin не влияет, и все свойства модулей пустые. Возможно, доступный модуль имеет только начальное значение, а дальше по конвейеру заменяется новый экземпляр. Я собираюсь просто поместить переменную flag в global.asax и использовать ее, чтобы заставить signedin только подписаться на один раз. Я собираюсь изменить свой вопрос, чтобы отразить новый метод. –

2

Я создал класс, производный от ClaimsAuthenticationManager. Существует только один метод, который вы должны переопределить, что

public virtual IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal); 

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

Мой класс выглядит примерно так:

public override IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal) 
    { 
     if (incomingPrincipal.Identity.IsAuthenticated) 
     { 
      var identity = incomingPrincipal.Identity as IClaimsIdentity;     
      User user = null; 

      // Get name identifier and identity provider 
      var nameIdentifierClaim = identity.Claims.SingleOrDefault(c => c.ClaimType.Equals(ClaimTypes.NameIdentifier, StringComparison.OrdinalIgnoreCase)); 
      var identityProviderClaim = identity.Claims.SingleOrDefault(c => c.ClaimType.Equals(CustomClaimTypes.IdentityProviderClaimType, StringComparison.OrdinalIgnoreCase)); 

      if (nameIdentifierClaim == null || identityProviderClaim == null) 
      { 
       throw new AuthenticationErrorException("Invalid claims", "The claims provided by your Identity Provider are invalid. Please contact your administrator."); 
      } 

      try 
      { 
       //checking the database here... 
       using (var context = new CloudContext()) 
       { 
        user = (from u in context.Users 
          where u.IdentityProvider == identityProviderClaim.Value && 
            u.NameIdentifier == nameIdentifierClaim.Value && 
            !u.Account.PendingDelete 
          select u).FirstOrDefault(); 
       } 
      } 
      catch (System.Data.DataException ex) 
      { 
       Console.WriteLine(ex.Message); 
       if (ex.InnerException != null) 
        Console.WriteLine(ex.InnerException); 
       throw; 
      } 

     } 

     return incomingPrincipal; 
    } 

Тогда в вашем web.config, вы добавить раздел в <microsoft.identitymodel> области, а так:

 <claimsAuthenticationManager type="CloudAnalyzer.UI.Security.CloudAnalyzerClaimsAuthenticationManager" /> 

Я узнал этот трюк из Пример приложения находится здесь: Windows Azure Marketplace. Даже если вы не собираетесь публиковать в Window Azure Marketplace, это хороший пример с некоторыми полезными фрагментами кода, которые вы можете использовать для интеграции ACS.

+0

Удивительно, я собираюсь попробовать это. Если бы я хотел добавить заявку на коллекцию в этот момент, ее можно было бы ввести в токен безопасности и быть доступным по следующему запросу? Я сделаю больше исследований, поэтому не стоит беспокоиться, если вам также нужно будет найти их. –

+0

Да, вы можете добавить заявку здесь. В приведенной выше ссылке I добавляется пользовательское требование для «tenantId», которое является учетной записью, к которой принадлежит пользователь. Образец имеет метод «UpdateClaims», который запускается в этом общедоступном переопределении метода IClaimsPrincipal Authenticate для проверки поданных заявок, а также пользовательских. Проверьте это ... – ChrisW