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

时间:2012-11-26 21:53:08

标签: web-services authentication authorization servicestack basic-authentication

现在我正在玩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我尝试添加here所述的授权请求标头:

enter image description here

查看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; } }

1 个答案:

答案 0 :(得分:4)

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

由于问题we have updated CustomAuthenticationMvc是一个很常见的问题,因此可以展示可能的解决方案。