2014-01-08 4 views
3

Я выполнил заказ CredentialsAuthProvider для моей аутентификации и использовал его со стандартным хранилищем сеансов памяти.Как использовать мой собственный поставщик проверки подлинности ServiceStack с помощью Redis?

Теперь я попытался изменить память сеанса Redis и добавил это к моему Configure() метода в AppHost:

container.Register<IRedisClientsManager>(c => 
    new PooledRedisClientManager("localhost:6379")); 

container.Register<ICacheClient>(c => (ICacheClient)c 
    .Resolve<IRedisClientsManager>() 
    .GetCacheClient()).ReusedWithin(Funq.ReuseScope.None); 

Теперь, когда я аутентифицировать, я могу видеть, что ключ с urn:iauthsession:... добавляется к моему Redis сервер. Но все маршруты с атрибутом [Authenticate] дают ошибку 401 Unauthorized.

The CustomCredentialsAuthProvider реализован так:

public class CustomCredentialsAuthProvider : CredentialsAuthProvider 
{ 
    public override bool TryAuthenticate(IServiceBase authService, string userName, string password) 
    { 
     if (userName != string.Empty && password != string.Empty) 
     { 
      // Database call ... 
      var session = (CustomSession)authService.GetSession(); 
      session.ClientId = login.ClientId; 
      // Fill session... 
      authService.SaveSession(session, SessionExpiry); 
      return true; 
     } 
     return false; 
    } 
} 

ServiceStack Версия: 3.9.71

EDIT:

Я попытался переопределить CredentialsAuthProviderIsAuthorized метод, но без успеха.

Но я наследую свой объект сеанса от AuthUserSession, который также имеет метод IsAuthorized. Когда я возвращаю true из этого метода, сеанс Redis работает с атрибутом Authenticate.

public class CustomSession : AuthUserSession 
{ 
    public int ClientId { get; set; } 
    ... 

    public override bool IsAuthorized(string provider) 
    { 
     return true; 
    } 
} 
+0

Я не думаю, что это связано с вашей проблемы, но вы не должны заполнять сессию в ' TryAuthenticate'. Предпочтительная практика - в методе «OnAuthenticated». [См. Здесь] (https://github.com/ServiceStackV3/ServiceStackV3/wiki/Authentication-and-authorization).Кажется, что существует проблема с возвратом сеанса из Redis в 'AuthenticationAttribute'. Чтобы отладить это, я бы начал с удаления атрибута из одного из ваших обработчиков действий и попробуйте добавить в него 'base.Request.GetSession()' и посмотреть, правильно ли восстановлен ваш сеанс в вашей службе. – Scott

+0

@Scott Я могу получить сеанс в обработчике действий, когда я удаляю атрибут '[Authenticate]'. Так кажется, что это ошибка в 'AuthenticationAttribute'? –

+2

Это не ошибка в вашей реализации. Я думаю, вам нужно установить 'session.UserAuthName' и' session.UserAuthId', если вы не переопределяете метод 'CredentialProviders'' IsAuthorized'. – Scott

ответ

1

Я не мог придумать способ, чтобы получить [Authenticate] атрибут для работы с хранилищем Redis.

я должен был написать обычай [SessionAuth] Attribute

public class SessionAuthAttribute : RequestFilterAttribute 
{ 
    public ICacheClient cache { get; set; } 
    public string HtmlRedirect { get; set; } 

    public SessionAuthAttribute() 
    { 
    } 

    public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto) 
    { 
     string sessionId = req.GetSessionId(); 
     if (string.IsNullOrEmpty(sessionId)) 
     { 
      HandleNoSession(req, res); 

     } 
     else 
     { 
      var session = cache.Get<CustomSession>("urn:iauthsession:" + sessionId); 
      if (session == null || !session.IsAuthenticated) 
      { 

       HandleNoSession(req, res); 
      } 
     } 
    } 

    private void HandleNoSession(IHttpRequest req, IHttpResponse res) 
    { 

     if (req.ResponseContentType.MatchesContentType(MimeTypes.Html)) 
     { 

      res.RedirectToUrl(HtmlRedirect); 
      res.End(); 

     } 
     res.StatusCode = (int)HttpStatusCode.Unauthorized; 
     res.Write("not authorized"); 
     res.Close(); 
    } 
} 

В моем методе AppHost Configure() Я просто зарегистрировать SessionFeature и IRedisClientsManager/ICacheClient:

Plugins.Add(new SessionFeature()); 

container.Register<IRedisClientsManager>(c => new PooledRedisClientManager("localhost:6379")); 

container.Register<ICacheClient>(c => (ICacheClient)c.Resolve<IRedisClientsManager>() 
     .GetCacheClient()).ReusedWithin(Funq.ReuseScope.None); 

Класс CustomSession наследуется от AuthUserSession :

public class CustomSession : AuthUserSession 
{ 
    public int ClientId { get; set; } 
    ... 
} 

И я ха ве нормальный маршрут обслуживания на/логин/аутентификации для аутентификации части и маршрута в/Логин/выход из системы для удаления сеанса:

public class LoginService : Service 
{ 
    public ICacheClient cache { get; set; } 

    public object Post(AuthRequest request) 
    { 
     string userName = request.UserName; 
     string password = request.Password; 

     // check login allowed 

     if (IsAllowed) 
     { 

      var session = SessionFeature.GetOrCreateSession<CustomSession>(cache); 

      session.ClientId = login.ClientId; 
      ... 
      session.IsAuthenticated = true; 
      session.Id = SessionFeature.GetSessionId(); 

      this.SaveSession(session, TimeSpan.FromSeconds(30 * 60)); 


      return true; 
     } 

     return false; 
    } 


    [SessionAuth] 
    public object Any(LogoutRequest request) 
    { 
     this.RemoveSession(); 
     return true; 
    } 
} 

}

Я все еще заинтересован в решение, которое работает с normal [Authenticate] Атрибут.

3

Атрибут Authenticate вызывает IsAuthorized класса AuthUserSession. В моем случае, чтобы заставить его работать с клиентом кэша Redis, я сделал следующее

public override bool IsAuthorized(string provider) 
{ 
    string sessionKey = SessionFeature.GetSessionKey(this.Id); 
    ICacheClient cacheClient = AppHostBase.Resolve<ICacheClient>(); 

    CustomUserSession session = cacheClient.Get<CustomUserSession>(sessionKey); 

    if (session == null) 
    { 
     return false; 
    } 

    return session.IsAuthenticated; 
}