我在OWIN ASP.NET C#web API中使用OWIN OAuthAuthorizationServer
库来生成和处理承载令牌。
现在,我有一个端点(您在OAuthAuthorizationServerOptions
结构中设置),它接受来自前端的grant_type
,username
和password
字段。我创建了一个执行验证的提供程序类,然后相应地调用context.Validated()
或context.SetError()
。然后中间件处理生成令牌并将其返回给用户,并“接管”登录端点,在内部完成所有工作。
现在,我正在为我的API添加一项新功能,用户可以在其中更改“角色”(例如,管理员可以将自己设置为常规用户以查看其工作结果,用户可以在多个角色中进行选择,因为我已经通过持票令牌处理了这个(我在那里存储用户的角色,我的所有端点都使用持票令牌来确定当前角色),我现在有理由从API更新持票令牌的内容后端。
我要做的是允许前端调用接受参数的端点(例如api/set_role
)。用户请求某个角色,其当前的承载令牌将伴随该请求。然后,服务器将检查相关用户是否被允许使用该特定角色,如果是,则生成新令牌并将其返回给响应主体中的用户。然后,前端将在本地存储中更新其令牌。或者,当然,如果不允许用户切换到该角色,后端将返回适当的错误,并且前端会做出相应的反应。
为此,我基本上希望能够手动生成令牌。与我在登录提供程序中使用identity.AddClaim()
的方式类似,我希望能够在API代码中的任意位置执行此操作。该方法将负责将任何必要的现有信息(例如用户的用户名)转移到新令牌中,因为它已经具有现有信息。
我想要的伪代码:
if (!userCanUseRole(requestedRoleId)) return Request.CreateErrorResponse(...);
// we have a struct containing parsed information for the current token in the variable cToken
bearerToken newToken = new bearerToken();
newToken.AddClaim(new Claim("user", cToken.user));
newToken.AddClaim(new Claim("role", requestedRoleId));
string tokenToReturnToFrontend = newToken.getTokenString(); // string suitable for using in Authorization Bearer header
return Request.CreateResponse(new StringContent(tokenToReturnToFrontend));
我对“刷新”令牌并不太熟悉,但我现在使用它们的唯一方法是延长令牌到期时间。为此,前端显式请求刷新令牌并提供自己的刷新令牌,后端只需复制到新令牌并编辑到期时间。这个问题是有一种获取刷新令牌的方法,因为我现在至少有一个其他原因来刷新令牌(可能,未来的发展可能会增加更多的理由来在不同时间更改令牌内容),然后我必须处理在某处存储瞬态数据(例如“当请求刷新令牌时,用户想要做什么?它已经太久了,因为他们要求这样做?等等)它会是如果我能按照OAuthAuthorizationServer
本身的方式生成一个承载令牌,就会容易得多。(我知道它使用MachineKey来做到这一点,但我不知道究竟是怎么做的,也不管怎么做我想做的事。)
值得注意的是:在另一个项目中,我提供了internal
对传递给授权服务器实例的OAuthBearerAuthenticationOptions
类的访问权限,并且能够使用它来解码 a测试中的持票人令牌。我没有看到任何明显的想法会让我以这种方式编码一个承载令牌。
AccessTokenFormat
类它应该做我想要的。我写了这段代码:
Microsoft.Owin.Security.AuthenticationTicket at = new Microsoft.Owin.Security.AuthenticationTicket(new ClaimsIdentity
{
Label="claims"
}
, new Microsoft.Owin.Security.AuthenticationProperties
{
AllowRefresh=true,
IsPersistent=true,
IssuedUtc=DateTime.UtcNow,
ExpiresUtc=DateTime.UtcNow.AddMinutes(5),
});
at.Identity.AddClaim(new Claim("hello", "world"));
string token = Startup.oabao.AccessTokenFormat.Protect(at);
return Request.CreateResponse(HttpStatusCode.OK, new StringContent(token, System.Text.Encoding.ASCII, "text/plain"));
这似乎应该有效。 (我再次允许访问传递给OAuthBearerAuthenticationOptions
实例的OAuthAuthorizationServer
类。)但是,此代码会抛出ArgumentNull
异常。 stacktrace表示它正在写入BinaryWriter,但OWIN代码将空值传递给BinaryWriter上的Write
方法。
仍然没有解决方案。
答案 0 :(得分:2)
我确实找到了使这项工作的代码。有人可能会说我没有正确使用OAuth,但严格来说,这段代码可以完成我想要的任务 - 在任意点的代码中生成一个令牌并获取字符串。
首先,正如我所说,我必须提供对OAuthBearerAuthenticationOptions
类实例的访问。当OAuth服务器初始化时,我猜测它会使用用于令牌的所有各种对象填充此类。关键是我们可以访问Protect
和Unprotect
,它们可以直接编码和解码承载令牌。
此代码将生成一个令牌,假设oabao
是已传递给OAuthBearerAuthenticationOptions
实例的OAuthAuthorizationServer
类:
Microsoft.Owin.Security.AuthenticationTicket at = new Microsoft.Owin.Security.AuthenticationTicket(new ClaimsIdentity("Bearer", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"),
new Microsoft.Owin.Security.AuthenticationProperties
{
AllowRefresh = true,
IsPersistent = true,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddDays(1) // whenever you want your new token's expiration to happen
});
// add any claims you want here like this:
at.Identity.AddClaim(new Claim("userRole", role));
// and so on
string token = oabao.AccessTokenFormat.Protect(at);
// You now have the token string in the token variable.