现在我正在玩ServiceStack及其Authentication and authorization支持。
在Use Cases project上使用CustomAuthenticationMvc
(网络服务Host
应用),在尝试了解身份验证的工作原理时,我这样做了:
public class AppHost : AppHostBase
{
public AppHost() : base("Basic Authentication Example",
typeof(AppHost).Assembly) { }
public override void Configure(Container container)
{
// register storage for user sessions
container.Register<ICacheClient>(new MemoryCacheClient());
container.Register<ISessionFactory>(c => new SessionFactory(
c.Resolve<ICacheClient>()));
//Register AuthFeature with custom user session and Basic auth provider
Plugins.Add(new AuthFeature(
() => new CustomUserSession(),
new AuthProvider[] { new BasicAuthProvider() }
) );
var userRep = new InMemoryAuthRepository();
container.Register<IUserAuthRepository>(userRep);
//Add a user for testing purposes
string hash;
string salt;
new SaltedHash().GetHashAndSaltString("test", out hash, out salt);
userRep.CreateUserAuth(new UserAuth
{
Id = 1,
DisplayName = "DisplayName",
Email = "as@if.com",
UserName = "john",
FirstName = "FirstName",
LastName = "LastName",
PasswordHash = hash,
Salt = salt,
}, "test");
}
}
服务实现是着名的Hello World,在请求DTO正上方应用了[Authenticate]
属性...
[Authenticate]
[Route("/hello")]
[Route("/hello/{Name}")]
public class HelloRequest : IReturn<HelloResponse>
{
public string Name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
public class HelloService : IService<HelloRequest>
{
public object Execute(HelloRequest request)
{
return new HelloResponse
{
Result = "Hello, " + request.Name
};
}
}
将控制台应用程序用作Client
,我有以下代码:
static void Main(string[] args)
{
// The host ASP.NET MVC is working OK! When I visit this URL I see the
// metadata page.
const string BaseUrl = "http://localhost:8088/api";
var restClient = new JsonServiceClient(BaseUrl);
restClient.SetCredentials("john", "test");
HelloResponse response = restClient.Get<HelloResponse>("/hello/Leniel");
Console.WriteLine(response.Result);
}
这里的问题是我不认为restClient.SetCredentials("john", "test");
正如我所期望的那样工作,因为webservice调用restClient.Get<HelloResponse>("/hello/Leniel");
正在抛出异常。我看到我被重定向到登录页面......我认为设置凭据就可以调用Web服务了。情况并非如此。
我做错了什么?我计划从MonoTouch iOS应用程序调用此Web服务,用户将在一个简单的对话框窗口中输入他的用户名和密码,但在此之前,我希望在这个简单的控制台应用程序中使用它。
编辑1
我尝试使用此代码发送身份验证请求(如此thread所示):
var authResponse = restClient.Send<AuthResponse>(new Auth
{
UserName = "john",
Password = "test",
RememberMe = true,
});
但抛出异常:
类型定义应以'{'开头,期待序列化类型 'AuthResponse',以字符串开头:
<head>
看起来我有一个配置错误的服务,因为它一直将我重定向到默认的ASP.NET MVC Login
页面(参见下面的Fiddler截图)。我还将通过AuthFeature
的{{1}}注册更改为null
。
HtmlRedirect
编辑2
查看Fiddler中的Auth检查员,我可以看到:
//Register AuthFeature with custom user session and Basic auth provider
Plugins.Add(new AuthFeature(
() => new CustomUserSession(),
new AuthProvider[] { new BasicAuthProvider() }
) { HtmlRedirect = null });
现在,为什么我会获得401未经授权的身份?鉴于我在内存中设置用户进行测试,它不应该只是工作吗?
如何在示例控制台应用程序中传递请求标头?
如果我在控制台应用中执行:
Authorization Header is present: Basic am9objp0ZXN0
Decoded Username:Password= john:test
我得到401未经授权的回复...
编辑3
借助desunit的答案和代码添加,我设法使用以下代码使用Console App身份验证:
restClient.AlwaysSendBasicAuthHeader = true;
我现在想知道以下内容:在控制台应用程序中,我应该始终发送基本身份验证标头吗?如果我删除该行,则身份验证失败,我没有得到class Program
{
const string BaseUrl = "http://localhost:8088/api";
static void Main(string[] args)
{
var restClient = new JsonServiceClient(BaseUrl);
restClient.SetCredentials("john", "test");
restClient.AlwaysSendBasicAuthHeader = true;
HelloResponse response = restClient.Get<HelloResponse>("/hello/Leniel");
Console.WriteLine(response.Result);
}
}
//Response DTO
//Follows naming convention
public class HelloResponse
{
public string Result { get; set; }
}
答案 0 :(得分:4)
问题与ServiceStack本身无关,而是与ASP.NET Web如何处理401错误代码有关。您可以使用自定义IHttpModule
来解决此问题,这会禁止重定向到“登录”表单。有关该问题的更多详细信息,请参阅here。
由于问题we have updated CustomAuthenticationMvc
是一个很常见的问题,因此可以展示可能的解决方案。