首页 文章

两个不同的OWIN应用程序可以授权OAuth2承载访问令牌吗? [重复]

提问于
浏览
4

这个问题在这里已有答案:

我有两个Web API:

  • Identity API . 它实现身份验证,用户注册和OAuth客户端注册和身份验证 .

  • Product API . 一组RESTful API,用于处理我的业务 .

我使用 Identity API 来验证资源所有者(即具有用户密码凭据的用户)以使用OAuth2 OWIN中间件获取承载令牌 .

我的问题是,一旦我从 Identity API 获得访问令牌,我想用它来授权对 Product API 的请求 .

这两个API都访问同一个数据库,两者现在都在同一台机器上 .

当我尝试对 Product API 执行请求时,我得到响应消息 "Authorization has been denied for this request" ,同时执行 Identity API 的请求完美无瑕 .

关键是我已经派生了 OAuthAuthorizationServerProvider 以满足一些自定义身份验证/授权要求,但是在向 Product API 发出请求时它永远不会到达这一点( ValidateClientAuthenticationGrantResourceOwnerCredentials 方法永远不会被调用) .

我已经放弃了OWIN中间件的顺序可能会影响身份验证流程:两个API都以相同的方式配置 .

前几天......

...在尝试以这种方式工作之前,我正在考虑创建自定义 OAuthAuthorizationServerProvider 和ASP.NET Identity用户存储以在内部实际查询 Identity API ,因此,将在发出访问权限的OWIN应用程序中验证身份验证和授权 . 令牌 .

我已经为ASP.NET Identity(GitHub repository)实现了一个自定义用户存储,我还没有实现 OAuthAuthorizationServerProvider 来发出HTTP请求,而不是直接使用底层数据库 .

Anwyay,我想知道我是否可以避免这样做一段时间, and if I can issue access tokens from an OWIN app and consume access tokens from a different OWIN app with also a different host and port.

更新:调试System.Web.Http

我从ASP.NET Web Stack GitHub repository下载了 System.Web.Http 源代码,我将've also compiled it, and I' ve链接到已编译的程序集到我的 Product API WebAPI项目以调试 AuthorizeAttribute .

收到整个承载令牌,但 actionContext.ControllerContext.RequestContext.Principalnull . 我怀疑某些与OAuth相关的中间件没有解密并将用户分配给整个属性 .

重点是 Identity API 上的相同令牌 .

检查以下屏幕截图,我可以在其中演示正在接收的持有者令牌:

enter image description here

更新2:Identity API可以使用发出的访问令牌授权请求...

我可以确认访问令牌用于授权对Identity API 's resources (for example, I' ve实现 UserController 的请求以让 Identity API 注册和管理用户,并且大多数控制器操作都标有 [Authorize] 属性...) .

1 回答

  • 10

    是的,您可以将授权服务器和资源服务器分离 . 他们可以生活在不同的owin应用程序中,不仅如此,它们甚至可以存在于不同的服务器上 .

    authorization server 将负责向您的客户端应用程序发出访问令牌,并最终管理用户和角色 .

    resource server 将托管受保护资源,接受授权服务器发布的访问令牌 .

    查看您的基础架构, Identity API 将是授权服务器,而 Product API 将是您的资源服务器 .

    授权服务器需要配置和使用 OAuthAuthorizationServerProvider 的实现 .
    在你的创业公司你会做这样的事情:

    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    
    var OAuthOptions = new OAuthAuthorizationServerOptions
    {
        AllowInsecureHttp = true,
        TokenEndpointPath = new PathString("/oauth/Token"),
        AccessTokenExpireTimeSpan = TimeSpan.FromHours(8),
        Provider = new MyAuthorizationServerProvider(),
        // RefreshTokenProvider = new MyRefreshTokenProvider(DateTime.UtcNow.AddHours(8))
    };
    
    app.UseOAuthAuthorizationServer(OAuthOptions);
    app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    

    如您所见,我已使用 MyAuthorizationServerProvider 作为身份验证的自定义提供程序 .

    它负责验证客户端( ValidateClientAuthentication )并授予访问资源的授权( GrantResourceOwnerCredentials ) .

    GrantResourceOwnerCredentials 将检查客户端的凭据(用户名和密码)是否有效并释放有效令牌:

    var ticket = new AuthenticationTicket(identity, props);
    context.Validated(ticket);
    

    AuthenticationTicket 收到 ClaimsIdentity 对象和 AuthenticationProperties 的集合 .

    您通常会在此处添加用户名声明和角色:

    ClaimsIdentity identity = new ClaimsIdentity(context.Options.AuthenticationType);
    identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
    identity.AddClaim(new Claim(ClaimTypes.Role, "Users"));
    

    最后,您可能想要使用其他类型的声明 .
    AuthenticationProperties 集合将定义您要传递给客户端的扩展信息:

    var props = new AuthenticationProperties(new Dictionary<string, string>
    {
        { 
        "name", "John"
        },
        { 
        "surname", "Smith"
        },
        { 
        "age", "40"
        },
        { 
        "gender", "Male"
        }
    });
    

    您可以查看此github repo以查看实现 .

    您的资源服务器(负责管理业务信息的RESTful API)不必重新实现整个授权/身份验证层 .

    在您的启动( Product API )中,您只需指示api使用和使用承载令牌:

    public void Configuration(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();
    
        OAuthBearerAuthenticationOptions OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
        app.UseOAuthBearerAuthentication(OAuthBearerOptions);
    
        WebApiConfig.Register(config);
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        app.UseWebApi(config);
    }
    

    您的受保护资源将是这样的:

    [Authorize(Roles = "Users")]
    public class ProductsController : ApiController
    {
        public Models.Product GetProduct(string id)
        {
            var identity = User.Identity as ClaimsIdentity;
    
            return new Models.Product();
        }
    }
    

    正如您所看到的,我使用了 Authorize 属性,因为我只想授权某种类型的用户 .

    NOTE:

    如果要将 authorization serverresource server 托管到不同的计算机上,则必须确保在两台服务器上共享相同的 machineKey ,否则资源服务器将无法解密 authorization server 释放的承载令牌:

    <system.web>
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
        <machineKey validationKey="VALUE GOES HERE" 
                    decryptionKey="VALUE GOES HERE" 
                    validation="SHA1" 
                    decryption="AES"/>
    </system.web>
    

    我建议你阅读这篇article以找到关于所涉及的所有部分的非常好的解释 .

    Taisser也是另一个他经历过的地方使用Json Web Tokens实现相同结果的相同过程 .

相关问题