servicestack,dotnetopenauth,Oauth 2.0,servicestack,Dotnetopenauth" /> servicestack,dotnetopenauth,Oauth 2.0,servicestack,Dotnetopenauth" />

Oauth 2.0 如何通过DotNetOpenAuth使用OAuth2访问令牌授权对ServiceStack资源的访问?

Oauth 2.0 如何通过DotNetOpenAuth使用OAuth2访问令牌授权对ServiceStack资源的访问?,oauth-2.0,servicestack,dotnetopenauth,Oauth 2.0,servicestack,Dotnetopenauth,我已经使用DotNetOpenAuth创建了一个OAuth2授权服务器,该服务器工作正常-我正在使用资源所有者密码流,并成功地将用户凭据交换为访问令牌 现在,我想使用该访问令牌从ServiceStack API中的安全端点检索数据,但我不知道如何做到这一点。我已经检查了ServiceStack中包含的Facebook、Google等提供商,但不清楚我是否应该遵循相同的模式 我想要达到的(我想!)是 OAuth客户端(我的应用程序)要求资源所有者('Catherine Smith')提供凭据 客户

我已经使用DotNetOpenAuth创建了一个OAuth2授权服务器,该服务器工作正常-我正在使用资源所有者密码流,并成功地将用户凭据交换为访问令牌

现在,我想使用该访问令牌从ServiceStack API中的安全端点检索数据,但我不知道如何做到这一点。我已经检查了ServiceStack中包含的Facebook、Google等提供商,但不清楚我是否应该遵循相同的模式

我想要达到的(我想!)是

  • OAuth客户端(我的应用程序)要求资源所有者('Catherine Smith')提供凭据
  • 客户端向授权服务器提交请求,接收访问令牌
  • 客户端资源服务器请求安全的资源
    GET/users/csmith/photos
    • 访问令牌包含在HTTP头中,例如
      授权:承载1234abcd…
  • 资源服务器解密访问令牌以验证资源所有者的身份
  • 资源服务器检查资源所有者是否有权访问请求的资源
  • 资源服务器资源返回给客户端
  • 步骤1和2正在工作,但我无法确定如何将DotNetOpenAuth资源服务器代码与ServiceStack授权框架集成

    有没有一个例子可以说明我是如何做到这一点的?我在上找到了一篇类似的StackOverflow文章,但它不是一个完整的解决方案,而且似乎没有使用ServiceStack授权提供程序模型

    编辑:再详细一点。这里有两种不同的网络应用。一个是身份验证/授权服务器-它不承载任何客户数据(即没有数据API),但公开了/oauth/token方法,该方法将接受用户名/密码并返回OAuth2访问令牌和刷新令牌,还提供令牌刷新功能。这是基于ASP.NET MVC构建的,因为它与DotNetOpenAuth中包含的AuthorizationServer示例几乎相同。以后可能会替换它,但现在它是ASP.NET MVC

    对于实际的数据API,我使用ServiceStack,因为我发现它在公开ReSTful数据服务方面比WebAPI或MVC好得多

    在下面的例子中:

    客户端是在用户本地计算机上运行的桌面应用程序,身份验证服务器是ASP.NET MVC+DotNetOpenAuth,资源服务器是ServiceStack

    所需的DotNetOpenAuth代码的特定片段是:

    // scopes is the specific OAuth2 scope associated with the current API call.
    var scopes = new string[] { "some_scope", "some_other_scope" }
    
    var analyzer = new StandardAccessTokenAnalyzer(authServerPublicKey, resourceServerPrivateKey);
    var resourceServer = new DotNetOpenAuth.OAuth2.ResourceServer(analyzer);
    var wrappedRequest = System.Web.HttpRequestWrapper(HttpContext.Current.Request);
    var principal = resourceServer.GetPrincipal(wrappedRequest, scopes);
    
    if (principal != null) {
        // We've verified that the OAuth2 access token grants this principal
        // access to the requested scope.
    }
    
    因此,假设我的思路正确,我需要做的是在ServiceStack请求管道中的某个地方运行该代码,以验证API请求中的授权标头是否表示已授予对请求范围的访问权限的有效主体

    我开始认为实现这一点最合理的地方是我用来修饰ServiceStack服务实现的自定义属性:

    using ServiceStack.ServiceInterface;
    using SpotAuth.Common.ServiceModel;
    
    namespace SpotAuth.ResourceServer.Services {
        [RequireScope("hello")]
        public class HelloService : Service {
            public object Any(Hello request) {
                return new HelloResponse { Result = "Hello, " + request.Name };
            }
        }
    }
    
    这种方法还允许指定每个服务方法所需的范围。然而,这似乎与OAuth2背后的“可插拔”原则以及ServiceStack的AuthProvider模型内置的可扩展性挂钩背道而驰

    换句话说,我担心我正在用鞋子钉钉子,因为我找不到锤子…

    更新 经过进一步思考,您最初的想法是,创建RequiredScope属性将是一种更干净的方法。将其添加到ServiceStack管道与添加IHasRequestFilter接口、实现自定义请求过滤器一样简单,如下所述:

    然后按照您概述的方式装饰您的DTO或服务:

    using ServiceStack.ServiceInterface;
    using SpotAuth.Common.ServiceModel;
    
    namespace SpotAuth.ResourceServer.Services {
        [RequireScope("hello")]
        public class HelloService : Service {
            public object Any(Hello request) {
                return new HelloResponse { Result = "Hello, " + request.Name };
            }
        }
    }   
    
    您的RequireScope自定义过滤器几乎与相同,因此将其用作编码的起点

    或者,您可以将范围映射到权限。然后相应地装饰您的DTO或服务(详细信息),例如:

    [Authenticate]
    [RequiredPermission("Hello")]
        public class HelloService : Service {
            public object Any(Hello request) {
                return new HelloResponse { Result = "Hello, " + request.Name };
            }
        }
    
    通常ServiceStack在IAuthSession中调用方法boolHasPermission(字符串权限)。此方法检查IAuthSession中的列表权限是否包含所需的权限,因此,在自定义IAuthSession中,您可以覆盖HasPermission并将OAuth2作用域放在那里进行检查。

    好的,在使用调试器对各种库进行了大量单步检查之后,我认为您可以这样做:

    有两个关键的集成点。首先,服务器上使用的自定义筛选器属性用于修饰应使用OAuth2授权保护的资源端点:

     /// <summary>Restrict this service to clients with a valid OAuth2 access 
    /// token granting access to the specified scopes.</summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]
    public class RequireOAuth2ScopeAttribute : RequestFilterAttribute {
        private readonly string[] oauth2Scopes;
        public RequireOAuth2ScopeAttribute(params string[] oauth2Scopes) {
            this.oauth2Scopes = oauth2Scopes;
        }
    
        public override void Execute(IHttpRequest request, IHttpResponse response, object requestDto) {
            try {
                var authServerKeys = AppHostBase.Instance.Container.ResolveNamed<ICryptoKeyPair>("authServer");
                var dataServerKeys = AppHostBase.Instance.Container.ResolveNamed<ICryptoKeyPair>("dataServer");
                var tokenAnalyzer = new StandardAccessTokenAnalyzer(authServerKeys.PublicSigningKey, dataServerKeys.PrivateEncryptionKey);
                var oauth2ResourceServer = new DotNetOpenAuth.OAuth2.ResourceServer(tokenAnalyzer);
                var wrappedRequest = new HttpRequestWrapper((HttpRequest)request.OriginalRequest);
                HttpContext.Current.User = oauth2ResourceServer.GetPrincipal(wrappedRequest, oauth2Scopes);
            } catch (ProtocolFaultResponseException x) {
                // see the GitHub project for detailed error-handling code
                throw;
            }
        }
    }
    
    授权请求将成功;缺少令牌、令牌过期或作用域不足的请求将引发
    WebServiceException


    这仍然是很多概念验证的东西,但似乎工作得很好。我欢迎任何比我更了解ServiceStack或DotNetOpenAuth的人提供反馈。

    是否适合您的需要?这里是文档-这个包可能提供了一个有用的代码示例:关于授权,建议阅读内置角色和权限支持:这里是一个添加自定义OAuth提供程序的更完整示例,而不是您链接的示例:--您是对的。我没有看到任何将OAuth身份验证与角色和权限授权完全集成在一起的示例。请再试一次。ServiceStack在您的实现中扮演什么角色?我一直认为SS将提供资源,并且需要通过资源服务器确认授权。但是你上面的大纲
     /// <summary>Restrict this service to clients with a valid OAuth2 access 
    /// token granting access to the specified scopes.</summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]
    public class RequireOAuth2ScopeAttribute : RequestFilterAttribute {
        private readonly string[] oauth2Scopes;
        public RequireOAuth2ScopeAttribute(params string[] oauth2Scopes) {
            this.oauth2Scopes = oauth2Scopes;
        }
    
        public override void Execute(IHttpRequest request, IHttpResponse response, object requestDto) {
            try {
                var authServerKeys = AppHostBase.Instance.Container.ResolveNamed<ICryptoKeyPair>("authServer");
                var dataServerKeys = AppHostBase.Instance.Container.ResolveNamed<ICryptoKeyPair>("dataServer");
                var tokenAnalyzer = new StandardAccessTokenAnalyzer(authServerKeys.PublicSigningKey, dataServerKeys.PrivateEncryptionKey);
                var oauth2ResourceServer = new DotNetOpenAuth.OAuth2.ResourceServer(tokenAnalyzer);
                var wrappedRequest = new HttpRequestWrapper((HttpRequest)request.OriginalRequest);
                HttpContext.Current.User = oauth2ResourceServer.GetPrincipal(wrappedRequest, oauth2Scopes);
            } catch (ProtocolFaultResponseException x) {
                // see the GitHub project for detailed error-handling code
                throw;
            }
        }
    }
    
    // Create the ServiceStack API client and the request DTO
    var apiClient = new JsonServiceClient("http://api.mysite.com/");
    var apiRequestDto = new Shortlists { Name = "dylan" };
    
    // Wire up the ServiceStack client filter so that DotNetOpenAuth can 
    // add the authorization header before the request is sent
    // to the API server
    apiClient.LocalHttpWebRequestFilter = request => {
        // This is the magic line that makes all the client-side magic work :)
        ClientBase.AuthorizeRequest(request, accessTokenTextBox.Text);
    }
    
    // Send the API request and dump the response to our output TextBox
    var helloResponseDto = apiClient.Get(apiRequestDto);
    
    Console.WriteLine(helloResponseDto.Result);