¿Cómo puedo llenar un UserAuth de los valores en Redis?
servicestack authentication (1)
Esta es la configuración de autenticación de usuario personalizada en mi archivo global.asax
, pero actualmente estoy proporcionando a los usuarios manualmente en el método Configure
; ¿Es posible tomar valores de un servidor Redis?
Por ejemplo, si el usuario existe y la contraseña está bien, ¿puede completar estos detalles automáticamente?
Plugins.Add(new AuthFeature(()=>
new AuthUserSession(),
new IAuthProvider[]{ new BasicAuthProvider() }
));
container.Register<ICacheClient>(new MemoryCacheClient());
var userRepo = new InMemoryAuthRepository();
container.Register<IUserAuthRepository>(userRepo);
string hash, salt;
new SaltedHash().GetHashAndSaltString("password", out hash, out salt);
userRepo.CreateUserAuth(new UserAuth
{
Id = 1,
DisplayName = "Haluk",
Email = "hal",
UserName = "haluk",
FirstName = "haluk",
LastName = "yılmaz",
PasswordHash = hash,
Salt = salt
}, "password");
Sí, puede autenticarse contra una fuente de datos Redis. Puede usar el construido en RedisAuthRepository
en lugar del InMemoryAuthRepository
, o si tiene un conjunto de datos Redis existente que desea usar en lugar del modelo IAuthRepository
de IAuthRepository
, he incluido una solución para eso, por la cual extiende el BasicAuthProvider
. El primer método es el más directo:
Utilice el RedisAuthRepository
:
- Entonces necesitas establecer una conexión con Redis.
- Luego registre sus proveedores de autenticación.
- Registre el
RedisAuthRepository
, con el cual los proveedores verificarán las credenciales, y sea compatible conRegistrationFeature
private IRedisClientsManager redisClientsManager;
public override void Configure(Funq.Container container)
{
// Configure ServiceStack to connect to Redis
// Replace with your connection details
redisClientsManager = new PooledRedisClientManager("127.0.0.1:6379");
container.Register<IRedisClientsManager>(c => redisClientsManager);
container.Register<ICacheClient>(c => c.Resolve<IRedisClientsManager>().GetCacheClient()).ReusedWithin(Funq.ReuseScope.None);
// Setup the authorisation feature
Plugins.Add(new AuthFeature(()=>
new AuthUserSession(),
new IAuthProvider[]{ new BasicAuthProvider() }
));
// Use a RedisAuthRepository
var userRepo = new RedisAuthRepository(redisClientsManager);
container.Register<IUserAuthRepository>(userRepo);
// You can then register users as required using the RegistrationFeature
}
Alternativamente (si tiene un conjunto de datos de autenticación de usuario existente en Redis)
Puede hacerlo creando un proveedor de autenticación personalizado que amplíe el BasicAuthProvider
existente .
Para este código, también debe asegurarse de estar familiarizado con el cliente ServiceStack.Redis .
Extienda BasicAuthProvider
:
Este MyRedisBasicAuthProvider
amplía el BasicAuthProvider
existente, y en lugar de realizar la búsqueda de credenciales desde un IUserAuthRepository
como figura en su código de ejemplo, realiza una conexión Redis y hace coincidir el nombre de usuario con la entrada en Redis.
El código está completamente comentado, pero si hay algo que deseas más explicado, házmelo saber.
public class MyRedisBasicAuthProvider : BasicAuthProvider
{
// The key at which we will store the user profile. i.e user:john.smith or user:homer.simpson
// Replace this key with your format as required
public const string UserKeyFormat = "user:{0}";
MyUser CurrentUser;
// Gets an instance of a redis client
static IRedisClient GetRedisClient()
{
// Get the RedisClientsManager from the Container
var redisClientManager = HostContext.TryResolve<IRedisClientsManager>();
if(redisClientManager == null)
throw new Exception("Redis is not configured");
// Return a client
return redisClientManager.GetClient();
}
// This method is used to verify the credentials provided
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
// Get a Redis client connection
using(var redisClient = GetRedisClient())
{
// Get a typed Redis Client
var userClient = redisClient.As<MyUser>();
// Try to find a matching user in Redis
CurrentUser = userClient.GetValue(string.Format(UserKeyFormat, userName));
// Check the user exists & their password is correct (You should use a hashed password here)
return CurrentUser != null && password == CurrentUser.Password;
}
}
// This method is used to populate the session details from the user profile and other source data as required
public override IHttpResult OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo)
{
// Populate the session with the details of the current user
session.PopulateWith<IAuthSession, MyUser>(CurrentUser);
// Save the session
authService.SaveSession(session);
return null;
}
public static void AddUserToRedis(MyUser user)
{
using(var redisClient = GetRedisClient())
{
// Get a typed Redis Client
var userClient = redisClient.As<MyUser>();
// Add the user to Redis
userClient.SetEntry(string.Format(UserKeyFormat, user.Username), user);
}
}
}
En el código anterior he utilizado una clase MyUser
para representar el perfil de usuario que he almacenado en Redis, por supuesto puede personalizar esta clase para que coincida con los requisitos de su perfil de usuario. Esta es la clase de perfil de usuario básico:
public class MyUser
{
public string Username { get; set; }
public string Password { get; set; } // Replace with a hashed password
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Configuración de ServiceStack con Redis y su proveedor de autenticación personalizado:
Tendrá que configurar ServiceStack para usar Redis e indicarle que use su proveedor de autenticación personalizado. Para ello, agregue lo siguiente a su método Configure
en su AppHost
:
public override void Configure(Funq.Container container)
{
// Configure ServiceStack to connect to Redis
// Replace with your connection details
container.Register<IRedisClientsManager>(c => new PooledRedisClientManager("127.0.0.1:6379"));
container.Register<ICacheClient>(c => c.Resolve<IRedisClientsManager>().GetCacheClient()).ReusedWithin(Funq.ReuseScope.None);
// Add your custom credentials provider
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[] {
new MyRedisBasicAuthProvider()
}
));
// Add some test users. (If you have an existing Redis user source, you won''t need to add test users.)
MyRedisBasicAuthProvider.AddUserToRedis(new MyUser {
Username = "john.smith",
Password = "test",
Email = "[email protected]",
FirstName = "John",
LastName = "Smith",
});
MyRedisBasicAuthProvider.AddUserToRedis(new MyUser {
Username = "homer.simpson",
Password = "donuts",
Email = "[email protected]",
FirstName = "Homer",
LastName = "Simpson",
});
// Your other configuration settings ...
}
Notas:
En el ejemplo, no he usado una contraseña hash, para mantener el ejemplo sencillo, pero esto es trivial. Agregue otro campo public string Salt { get; set; }
public string Salt { get; set; }
public string Salt { get; set; }
a MyUser
entonces, en lugar de almacenar la contraseña simple en MyUser
guárdela como un hash de la contraseña y sal, es decir hashedPassword = HashAlgorithm(password + salt)
. Ya tienes un código para ello:
string hash, salt;
new SaltedHash().GetHashAndSaltString("password", out hash, out salt);
Por lo tanto, esta solución ahora usará una fuente de datos Redis para autenticar a los usuarios cuando se asegure un servicio utilizando el atributo [Authenticate]
. Al igual que con el proveedor básico estándar, las credenciales se autentican en la ruta estándar /auth/basic
.
Usar el proveedor de Credenciales en vez de Básico:
Si desea utilizar un proveedor de credenciales para las publicaciones de formularios, en lugar de la autenticación básica, puede simplemente reemplazar la palabra Basic
con Credentials
en el código anterior.
Espero que esto ayude.