使用 ServiceStack 使用 REST Web 服务时的用户身份验证

Posted

技术标签:

【中文标题】使用 ServiceStack 使用 REST Web 服务时的用户身份验证【英文标题】:User authentication when consuming a REST webservice with ServiceStack 【发布时间】:2012-11-27 01:29:20 【问题描述】:

ServiceStack 文档充满了关于如何使用服务器端实现用户身份验证的示例。但是如何在客户端设置用户凭据呢?

我使用 ServiceStack 来使用 JSON REST 服务,如下所示:

var restClient = new JsonServiceClient (baseUri);
var response = restClient.Get<MyResponse> ("/some/service");

如何向请求添加任何形式的身份验证?我想使用的网络服务使用OAuth 1.0,但我也有兴趣添加自定义身份验证。

在我的代码中,我之前已成功执行 OAuth 令牌交换,因此我已经拥有一个有效的访问令牌,现在需要使用此访问令牌及其 token_secret 签署每个 REST 请求。

【问题讨论】:

【参考方案1】:

ServiceStack 的AuthTests 显示了使用ServiceStack 服务客户端时的不同身份验证方式。默认情况下,BasicAuth 和 DigestAuth 内置在客户端中,例如:

var client = new JsonServiceClient(baseUri) 
    UserName = UserName,
    Password = Password,
;

var request = new Secured  Name = "test" ;
var response = client.Send<SecureResponse>(request);    

在幕后,ServiceStack 将尝试正常发送请求,但当请求被服务器拒绝和质询时,客户端将自动重试相同的请求,但这次使用 Basic/Digest Auth 标头。

当您知道您正在访问安全服务时,要跳过额外的跃点,您可以告诉客户端始终发送 BasicAuth 标头:

client.AlwaysSendBasicAuthHeader = true;

另一种身份验证方法是显式调用Auth 服务(这需要启用 CredentialsAuthProvider),例如:

var authResponse = client.Send<AuthResponse>(new Auth 
    provider = CredentialsAuthProvider.Name,
    UserName = "user",
    Password = "p@55word",
    RememberMe = true,  //important tell client to retain permanent cookies
);

var request = new Secured  Name = "test" ;
var response = client.Send<SecureResponse>(request);    

在成功调用Auth 服务后,客户端已通过身份验证,如果设置了 RememberMe,客户端将保留服务器在后续请求中添加的会话 Cookie,这将启用未来的请求从该客户端进行身份验证。

【讨论】:

感谢您的回答!我正在实施旧服务,因此无法更改身份验证方案。但是我找到了一种方法,请参阅我的答案。我必须不同意你的观点:) OAuth 也可以用于 Web 服务。 Tomboy/Ubuntu1 使用它来同步笔记。首次设置同步服务器时,它会触发浏览器并完成用户交互/授权。完成后,Tomboy 应用程序(使用它自己的 http 侦听器)被回调并传递一个访问令牌。获得后,访问令牌可以按照我的回答中的说明用于将来的所有进一步请求,而无需交互。【参考方案2】:

回答我自己,因为我找到了一种使用JsonServiceClient 中的LocalHttpWebRequestFilter 挂钩的好方法:

为了使用 OAuth 1.0a 保护 Web 服务,每个 http 请求都必须发送一个特殊的 Authorization: 标头。在此标头字段中,必须发送使用请求的某些特征作为输入数据的哈希(签名),例如主机名、请求 url 和 others。

现在看来,LocalHttpWebRequestFilter 在发出 http 请求之前由 ServiceStack 调用,并公开了底层的 HttpWebRequest 对象,人们可以在其中添加额外的标头并访问请求的所需字段。

所以我现在的解决方案基本上是:

var client = new JsonServiceClient (baseUri);

client.LocalHttpWebRequestFilter += (request) => 
    // compute signature using request and a previously obtained
    //  access token 
    string authorization_header = CalculateSignature (request, access_token);
  
    request.Headers.Add ("Authorization", authorization_header);
;
var response = client.Get<MySecuredResponse> ("/my/service");

请注意,我使用 Devdefined.OAuth 库来完成 CalculateSignature() 中的所有繁重工作。在上述服务调用之前,OAuth 要求的请求令牌的创建、获取用户授权以及将请求令牌交换为访问令牌是在 ServiceStack 之外完成的。

【讨论】:

我正在尝试做类似的事情,让 asp.net 客户端使用 servicestack 服务。关于您的实施的几个问题。你如何获得访问令牌?通过服务堆栈或其他方式?另外,我在 Devdefined.OAuth 中没有看到这个 CalculateSignature() 方法。它被替换了吗?提前感谢您的帮助! CalculateSignature 只是我放置的一个假人,您必须在那里进行 OAuth 操作。我为此使用 DevDefined.OAuth。令牌交换只进行一次,而不是每次请求。我使用 ServiceStack+DevDefined.OAuth 进行交换。整个项目是开源的,大家可以看看。令牌交换在这里完成:github.com/Dynalon/Rainy/blob/master/Rainy/WebService/OAuth/… 并且在每个请求上检查授权的过滤器在这里完成:github.com/Dynalon/Rainy/blob/master/Rainy/WebService/OAuth/…

以上是关于使用 ServiceStack 使用 REST Web 服务时的用户身份验证的主要内容,如果未能解决你的问题,请参考以下文章

ServiceStack 新的 API 动作匹配 Rest Verbs

在 IIS7.5 上找不到使用 serviceStack 的 PUT 处理程序

ServiceStack 请求 DTO 设计

ServiceStack.Redis:配置为使请求和响应类/ dto是同一类?

ServiceStack:错误未序列化到响应状态

如何在 ServiceStack 5.0 项目中使用来自 ServiceStack 4.0 的服务模型?