Как мне использовать свой собственный провайдер аутентификации ServiceStack с Redis?
Я реализовал кастом CredentialsAuthProvider
для моей аутентификации и использовал его по умолчанию в памяти сессии хранения.
Теперь я попытался изменить хранилище сеанса на 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
ошибка.
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
РЕДАКТИРОВАТЬ:
Я пытался переопределить CredentialsAuthProvider
IsAuthorized
метод, но без успеха.
Но я наследую свой сеансовый объект от AuthUserSession
который также имеет IsAuthorized
метод. Когда я возвращаю true из этого метода, сеанс Redis работает с Authenticate
Атрибут.
public class CustomSession : AuthUserSession
{
public int ClientId { get; set; }
...
public override bool IsAuthorized(string provider)
{
return true;
}
}
2 ответа
Я не мог найти способ получить [Authenticate]
Атрибут для работы с хранилищем Redis.
Я должен был написать обычай [SessionAuth]
атрибут
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; }
...
}
И у меня есть обычный сервисный маршрут в /login/auth для части аутентификации и /login/logout route для удаления сеанса:
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;
}
}
}
Я все еще заинтересован в решении, которое работает с нормальным [Authenticate]
Атрибут.
Authenticate
Атрибут вызывает IsAuthorized
из AuthUserSession
учебный класс. В моем случае, чтобы он работал с клиентом Redis cache, я сделал следующее
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;
}