具有基本身份验证和SetCredentials的ServiceStack Web服务

Len*_*rri 6 authentication authorization web-services basic-authentication servicestack

现在我正在使用ServiceStack及其身份验证和授权支持.

工作在CustomAuthenticationMvc(Web服务Host从应用程序)Use Cases项目,并试图了解该认证是如何工作的,我这样做:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

服务实现是着名的Hello World,其[Authenticate]属性应用于Request DTO上方...

[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
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

使用控制台应用程序作为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);
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是我不认为restClient.SetCredentials("john", "test");它正如我所期望的那样工作,因为webservice调用restClient.Get<HelloResponse>("/hello/Leniel");正在抛出异常.我看到我被重定向到登录页面......我认为设置凭据就可以调用Web服务了.情况并非如此.

我究竟做错了什么?我计划从MonoTouch iOS应用程序调用此Web服务,用户将在一个简单的对话框窗口中键入他的用户名和密码,但在此之前,我想让它在这个简单的控制台应用程序中运行.

编辑1

我尝试使用此代码发送auth请求(如此线程所示):

var authResponse = restClient.Send<AuthResponse>(new Auth
{
    UserName = "john", 
    Password = "test",
    RememberMe = true, 
});
Run Code Online (Sandbox Code Playgroud)

但抛出异常:

类型定义应该以'{'开头,期望序列化类型'AuthResponse',得到的字符串以:

<head>
Run Code Online (Sandbox Code Playgroud)

看起来我有一个配置错误的服务,因为它一直将我重定向到默认的ASP.NET MVC Login页面(参见下面的Fiddler截图).我也改变了AuthFeature注册null转到HtmlRedirect.

//Register AuthFeature with custom user session and Basic auth provider
Plugins.Add(new AuthFeature(
    () => new CustomUserSession(),
    new AuthProvider[] { new BasicAuthProvider() }
) {  HtmlRedirect = null });
Run Code Online (Sandbox Code Playgroud)

编辑2

与玩的Fiddler我尝试添加一个授权请求报头中描述这里:

在此输入图像描述

看着Fiddler的Auth检查员,我可以看到:

Authorization Header is present: Basic am9objp0ZXN0
Decoded Username:Password= john:test
Run Code Online (Sandbox Code Playgroud)

现在,为什么我会获得401未经授权的身份?鉴于我在内存中设置用户进行测试,它不应该只是工作吗?

如何在示例控制台应用程序中传递请求标头?

如果我在控制台应用程序中执行:

restClient.AlwaysSendBasicAuthHeader = true;
Run Code Online (Sandbox Code Playgroud)

我得到401未经授权的回复......

编辑3

在desunit的答案和代码添加的帮助下,我设法使用以下代码使用Console App身份验证:

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; }
}
Run Code Online (Sandbox Code Playgroud)

我现在想知道以下内容:在控制台应用程序中,我应该始终发送基本身份验证标头吗?如果我删除该行,验证失败,我没有得到HelloResponse.

des*_*nit 4

该问题与 ServiceStack 本身无关,而是与 ASP.NET Web 如何处理 401 错误代码有关。您可以使用自定义来解决此问题,IHttpModule该自定义会抑制重定向到登录表单。有关该问题的更多详细信息可以在此处阅读。

由于这是一个很常见的问题,我们更新了 CustomAuthenticationMvc项目来演示可能的解决方案。