为什么在使用 ServiceStack 客户端时我的 ServiceStack 服务会收到 401 响应

Why am I getting 401 responses from my ServiceStack Services when using ServiceStack client

我开发了一组 ServiceStack Web 服务,这些服务几个月来一直运行良好,主要来自使用 ServiceStack 客户端库的 WPF 应用程序。

由于与其他开发人员的服务出现了一些其他问题,我决定查看现有 WPF 应用程序与使用 Fiddler 的服务之间的请求和响应。

我注意到在对 Web 服务方法的每个请求中,它显示两个请求,第一个 returns 响应 401,第二个 returns 200。

我们所有的 Web 服务方法都设置为使用 "Any" 功能,允许来自客户端的任何动词 - 即 -

[Authenticate]
public object Any(DriverQuery request)
{
    var driver = DriverRepository.GetDriver<DriverEntity>(request.DriverUserId);
    return new DriverResponse { Driver = driver };
}

客户端仅使用 JsonServiceClient.Send 方法 - 即

var response = client.Send(new DriverQuery { DriverUserId = driverUserId });

我们正在使用基本身份验证。

我很担心为什么会这样,这是否正常,如果不正常,我做错了什么?

请求的附加信息

请求哪个returns 401响应:-

POST http://www.*******.uk/Api/jsv/reply/ClientsQuery HTTP/1.1
Accept: application/jsv
LoggedOnUserNameHeader: ******
User-Agent: ServiceStack .NET Client 4.038
Accept-Encoding: gzip,deflate
Content-Type: application/jsv
Host: dev.carbenefitsolutionstest.uk
Content-Length: 2
Expect: 100-continue

{}

401 响应

HTTP/1.1 401 Unauthorized
Cache-Control: private
Vary: Accept
Server: Microsoft-IIS/8.5
WWW-Authenticate: basic realm="/auth/basic"
X-Powered-By: ServiceStack/4.038 Win32NT/.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Access-Control-Allow-Origin, Authorization, Content-Type
X-AspNet-Version: 4.0.30319
Set-Cookie: ss-id=5JfAHCT3axaUqDA9eQTA; path=/; HttpOnly
Set-Cookie: ss-pid=yEGg9GfCSbwLZKL4RYsi; expires=Wed, 14-Mar-2035 08:47:48 GMT; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Sat, 14 Mar 2015 08:47:48 GMT
Content-Length: 0

请求其中 returns 200 响应:-

POST http://www.*******.uk/Api/jsv/reply/ClientsQuery HTTP/1.1
Accept: application/jsv
LoggedOnUserNameHeader: *******
User-Agent: ServiceStack .NET Client 4.038
Accept-Encoding: gzip,deflate
Content-Type: application/jsv
Host: dev.carbenefitsolutionstest.uk
Cookie: ss-id=5JfAHCT3axaUqDA9eQTA; ss-pid=yEGg9GfCSbwLZKL4RYsi
Authorization: Basic d2Vic2VydmljZTpzdDNybDFuZw==
Content-Length: 2
Expect: 100-continue

{}

200 次回应

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/jsv
Vary: Accept
Server: Microsoft-IIS/8.5
X-Powered-By: ServiceStack/4.038 Win32NT/.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Access-Control-Allow-Origin, Authorization, Content-Type
X-AspNet-Version: 4.0.30319
Set-Cookie: X-UAId=1; expires=Wed, 14-Mar-2035 08:47:48 GMT; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Sat, 14 Mar 2015 08:47:48 GMT
Content-Length: 78618

我创建了一个派生自 ServiceStack JsvServiceClient 的基础 class,它负责提供身份验证信息。其代码如下所示。

public abstract class BaseServiceClient : JsvServiceClient
{
    protected BaseServiceClient(string baseUri, TimeSpan serviceTimeout, string currentUserName)
        : base(baseUri)
    {
        Headers.Add(CustomHeaders.LoggedOnUserNameHeader, currentUserName);
        UserName = WebServiceSecurity.GetMasterUsername();
        Password = WebServiceSecurity.GetMasterPassword();
        Timeout = serviceTimeout;
    }
}

服务认证配置代码

Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {new BasicAuthProvider()}));
    var userRepository = new InMemoryAuthRepository();
    container.Register<IUserAuthRepository>(userRepository);

    string hash;
    string salt;

    new SaltedHash().GetHashAndSaltString(WebServiceSecurity.GetMasterPassword(), out hash, out salt);
userRepository.CreateUserAuth(new UserAuth
{
    Id = 1,
    UserName = *UserName*,
    PasswordHash = ******,
    Salt = ******,
    Roles = new List<string> { *Role* },
}, *Password*);

重要的是要注意,我们只调用了一次 Web 服务方法,并且这两个请求都是该调用的一部分

如果有人可以帮助或确认这是正常行为,我们将不胜感激。

非常感谢

西蒙

第一个请求失败,因为它向受保护的服务发送 non-Authenticated 请求,因此该服务正确响应 401 UnAuthenticated 以表明这一点。错误响应还表明服务支持 HTTP Basic AuthWWW-Authenticate: basic realm="/auth/basic" 响应 header。

当发出后续请求时,它包含可以在 HTTP Header Authorization: Basic d2Vic2VydmljZTpzdDNybDFuZw== 中看到的基本身份验证信息,因为它持有有效的 UserName/Password,然后成功。

您可以通过始终在每个请求中发送基本身份验证信息来跳过初始的未经身份验证的请求和身份验证质询响应。

您可以设置 AlwaysSendBasicAuthHeader 属性 以指示 ServiceStack's ServiceClients 始终在每个请求中发送基本授权信息,例如:

client.AlwaysSendBasicAuthHeader = true;

您可以在 ServiceClients AuthTests.cs.

中找到使用 ServiceStack ServiceClients 的其他身份验证示例