Ale*_*apa 2 .net c# authentication servicestack
我们可以为servicestack设置多个AuthProviders.但他们都应该使用一个用户存储库.有没有办法设置一个基本的auth提供程序和两个不同的存储库用于不同的路由?
简短的回答是,您不能简单地使用多个存储库.它不支持这一点的原因是因为CredentialsProvider使用AppHost依赖容器(IoC)来解析它IUserAuthRepository,所以它只需要一个存储库,除了它需要更多关于在路由中使用哪个存储库的信息.
你可以编写自己的CredentialsProvider,然后编写一个BasicAuthProvider从它扩展的新内容,但这对于简单的基本身份验证来说是很多工作.如果您正在使用InMemoryAuthRepository或者RedisAuthRepository您会发现即使您创建了单独的实例,存储库实际上也会合并,因为它们使用相同的缓存键.:(
// This doesn't work. The repositories will merge.
var repository1 = new InMemoryAuthRepository();
repository1.CreateUserAuth(new UserAuth { Id = 1, UserName = "cburns", FullName = "Charles Montgomery Burns" }, "excellent");
repository1.CreateUserAuth(new UserAuth { Id = 2, UserName = "bartsimpson", FullName = "Bart Simpson" }, "Ay caramba");
repository1.CreateUserAuth(new UserAuth { Id = 3, UserName = "homersimpson", FullName = "Homer J. Simpson" }, "donuts");
var repository2 = new InMemoryAuthRepository();
repository2.CreateUserAuth(new UserAuth { Id = 1, UserName = "thehulk", FullName = "The Hulk" }, "pebbles");
repository2.CreateUserAuth(new UserAuth { Id = 2, UserName = "captainamerican", FullName = "Captain America" }, "redwhiteblue");
repository2.CreateUserAuth(new UserAuth { Id = 3, UserName = "spiderman", FullName = "Spider Man" }, "withgreatpower");
Run Code Online (Sandbox Code Playgroud)
ServiceStack具有很好的可扩展性,您可以轻松地对自己的身份验证进行角色扮演.Basic Auth是一个非常简单的协议.
我只是创建了这个RequestFilterAttribute,允许您使用任意数量的自定义存储库.
完整的源代码这里 ServiceStack v4自托管应用程序
简单的自定义存储库. 您可以使用更复杂的存储库,并包括数据库查找等.但这很简单,用于演示目的:
public class MyUserRepository
{
public string Name { get; set; }
public Dictionary<string, string> Users { get; set; }
public MyUserRepository(string name, Dictionary<string, string> users = null)
{
Name = name;
Users = users ?? new Dictionary<string, string>();
}
}
Run Code Online (Sandbox Code Playgroud)
的RequestFilterAttribute. 即进行身份验证
public class BasicAuthAttribute : RequestFilterAttribute {
readonly string _realmName;
readonly string _repositoryName;
public BasicAuthAttribute(string realmName, string repositoryName = null)
{
_realmName = realmName;
_repositoryName = repositoryName ?? realmName;
}
public override void Execute(IRequest req, IResponse res, object requestDto)
{
// Get the correct repository to authenticate against
var repositories = HostContext.TryResolve<MyUserRepository[]>();
MyUserRepository repository = null;
if(repositories != null)
repository = repositories.FirstOrDefault(r => r.Name == _repositoryName);
// Determine if request has basic authentication
var authorization = req.GetHeader(HttpHeaders.Authorization);
if(repository != null && !String.IsNullOrEmpty(authorization) && authorization.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
{
// Decode the credentials
var credentials = Encoding.UTF8.GetString(Convert.FromBase64String(authorization.Substring(6))).Split(':');
if(credentials.Length == 2)
{
// Try and match the credentials to a user
var password = repository.Users.GetValueOrDefault(credentials[0]);
if(password != null && password == credentials[1])
{
// Credentials are valid
return;
}
}
}
// User requires to authenticate
res.StatusCode = (int)HttpStatusCode.Unauthorized;
res.AddHeader(HttpHeaders.WwwAuthenticate, string.Format("basic realm=\"{0}\"", _realmName));
res.EndRequest();
}
}
Run Code Online (Sandbox Code Playgroud)
用法:它的用法很简单.使用以下属性装饰您的操作方法或DTO:
public static class TestApp
{
[Route("/TheSimpsons", "GET")]
public class TheSimpsonsRequest {}
[Route("/Superheros", "GET")]
public class SuperherosRequest {}
public class TestController : Service
{
[BasicAuth("The Simpsons", "Simpsons")] // Requires a 'Simpsons' user
public object Get(TheSimpsonsRequest request)
{
return new { Town = "Springfield", Mayor = "Quimby" };
}
[BasicAuth("Superheros")] // Requires a user from 'Superheros'
public object Get(SuperherosRequest request)
{
return new { Publishers = new[] { "Marvel", "DC" } };
}
}
}
Run Code Online (Sandbox Code Playgroud)
[BasicAuth(string realmName, string repositoryName)]
realmName 是要在身份验证对话框中显示的名称repositoryName是要查找凭据的存储库的名称.它是可选的,如果排除它将使用realmName作为存储库名称.设置该演示在AppHost Configure方法中静态配置存储库:
public override void Configure(Funq.Container container)
{
container.Register<MyUserRepository[]>(c => new[]
{
new MyUserRepository("Simpsons", new Dictionary<string, string> {
{ "cburns", "excellent" },
{ "bartsimpson", "Ay caramba" },
{ "homersimpson", "donuts" }
}),
new MyUserRepository("Superheros", new Dictionary<string, string> {
{ "thehulk", "pebbles" },
{ "captainamerica", "redwhiteblue" },
{ "spiderman", "withgreatpower" }
})
});
}
Run Code Online (Sandbox Code Playgroud)
测试:导航到/TheSimpsons服务时会提示输入"辛普森一家"凭证,这里不允许使用"超级英雄"凭证.当你/Superheros反过来是真的.
我很欣赏这个解决方案确实偏离了ServiceStack身份验证提供程序.如上所述,可以使用ServiceStack身份验证提供程序从头开始构建您自己的身份验证,但这将很困难,超出了StackOverflow的范围.如果要执行此操作,可以通读现有提供程序并确定如何完成此操作.但是我的建议是,如果你不需要这种复杂性,那么请从上面的例子开始.
| 归档时间: |
|
| 查看次数: |
262 次 |
| 最近记录: |