我有两个Web API:
Identity API.它实现身份验证,用户注册和OAuth客户端注册和身份验证.
产品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发出请求时,它永远不会到达这一点(ValidateClientAuthentication
并且GrantResourceOwnerCredentials
永远不会调用方法).
我已经放弃了OWIN中间件的顺序可能会影响身份验证流程:两个API都以相同的方式配置.
...在尝试以这种方式工作之前,我正在考虑创建自定义OAuthAuthorizationServerProvider
和ASP.NET Identity用户存储以在内部实际查询Identity API,因此,将在发出访问权限的OWIN应用程序中验证身份验证和授权.令牌.
我已经为ASP.NET Identity(GitHub存储库)实现了一个自定义用户存储,我还没有实现一个OAuthAuthorizationServerProvider
来发出HTTP请求而不是直接使用底层数据库.
Anwyay,我想知道我是否可以避免这样做一段时间,如果我可以从OWIN应用程序发出访问令牌并使用不同的OWIN应用程序以及不同的主机和端口来访问令牌.
我System.Web.Http
从ASP.NET Web Stack GitHub存储库下载源代码,我也编译了它,并且已经将编译的程序集链接到我的Product API WebAPI项目进行调试AuthorizeAttribute
.
全承载令牌接收,但actionContext.ControllerContext.RequestContext.Principal
是null
.我怀疑某些与OAuth相关的中间件没有解密并将用户分配给整个属性.
重点是Identity API上的相同令牌.
检查以下屏幕截图,我可以在其中演示正在接收的持有者令牌:
我可以确认访问令牌用于授权对Identity API资源的请求(例如,我实现了一个UserController
让Identity API注册和管理用户,并且大多数控制器操作都标有[Authorize]
属性...).
是的,您可以将授权服务器和资源服务器分离.他们可以生活在不同的应用程序中,不仅如此,它们甚至可以存在于不同的服务器上.
该授权服务器将负责发行的访问令牌到你的客户端应用程序,并最终管理用户和角色.
该资源服务器将举办保护资源,接受授权服务器发布访问令牌.
查看您的基础架构,您的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
身份验证的自定义提供程序.
它负责验证client(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{ { "name", "John" }, { "surname", "Smith" }, { "age", "40" }, { "gender", "Male" } });
您可以查看此github 仓库以查看实施情况.
您的资源服务器,负责管理业务信息的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
属性,因为我只想授权某种类型的用户.
注意:
如果要将授权服务器和资源服务器托管到不同的计算机上,则必须确保machineKey
在两台服务器上共享相同内容,否则资源服务器将无法解密授权服务器发布的承载令牌:
我建议你阅读这篇文章,找到关于所涉及的所有部分的非常好的解释.
Taisser也是另一篇文章,他使用Json Web Tokens完成相同的过程来实现相同的结果.