在创建用户时发送带有 access_token、token_type 和 expires_in 的响应的想法是个好主意。但是,我会坚持使用 HttpClient 调用“/token”端点来完成这项任务。在生成令牌之前需要执行很多安全检查。由于这是安全性,我不会冒任何风险。我对使用行业专家提供的库/代码感到自在。
也就是说,我试图提出一个类,您可以在创建用户后调用该类来创建令牌。此代码取自 Microsoft 在其 Katana 项目中实施的 OAuth 授权服务器。您可以访问源here。如您所见,在创建令牌时发生了很多事情。
这是用于生成令牌的中间件类的修改版本。您必须提供正确的 OAuthAuthorizationServerOptions、上下文、用户名、密码、范围和客户端 ID 才能获得访问令牌。请注意,这是一个示例实现,可指导您朝着正确的方向前进。如果您想使用它,请彻底测试它。
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AspNetIdentity.WebApi.Providers;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Microsoft.Owin.Security.OAuth;
namespace WebApi.AccessToken
{
public class TokenGenerator
{
public string ClientId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public IList<string> Scope { get; set; }
private OAuthAuthorizationServerOptions Options { get; } =
new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat("http://localhost:59822")
};
public async Task<IList<KeyValuePair<string, string>>> InvokeTokenEndpointAsync(IOwinContext owinContext)
{
var result = new List<KeyValuePair<string, string>>();
DateTimeOffset currentUtc = Options.SystemClock.UtcNow;
// remove milliseconds in case they don't round-trip
currentUtc = currentUtc.Subtract(TimeSpan.FromMilliseconds(currentUtc.Millisecond));
AuthenticationTicket ticket = await InvokeTokenEndpointResourceOwnerPasswordCredentialsGrantAsync(owinContext, Options, currentUtc);
if (ticket == null)
{
result.Add(new KeyValuePair<string, string>("ERROR", "Failed to create acess_token"));
return result;
}
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(Options.AccessTokenExpireTimeSpan);
ticket = new AuthenticationTicket(ticket.Identity, ticket.Properties);
var accessTokenContext = new AuthenticationTokenCreateContext(
owinContext,
Options.AccessTokenFormat,
ticket);
await Options.AccessTokenProvider.CreateAsync(accessTokenContext);
string accessToken = accessTokenContext.Token;
if (string.IsNullOrEmpty(accessToken))
{
accessToken = accessTokenContext.SerializeTicket();
}
DateTimeOffset? accessTokenExpiresUtc = ticket.Properties.ExpiresUtc;
result.Add(new KeyValuePair<string, string>("access_token", accessToken));
result.Add(new KeyValuePair<string, string>("token_type", "bearer"));
TimeSpan? expiresTimeSpan = accessTokenExpiresUtc - currentUtc;
var expiresIn = (long)expiresTimeSpan.Value.TotalSeconds;
if (expiresIn > 0)
{
result.Add(new KeyValuePair<string, string>("expires_in", "bearer"));
}
return result;
}
private async Task<AuthenticationTicket> InvokeTokenEndpointResourceOwnerPasswordCredentialsGrantAsync(IOwinContext owinContext, OAuthAuthorizationServerOptions options, DateTimeOffset currentUtc)
{
var grantContext = new OAuthGrantResourceOwnerCredentialsContext(
owinContext,
options,
ClientId,
UserName,
Password,
Scope);
await options.Provider.GrantResourceOwnerCredentials(grantContext);
return grantContext.Ticket;
}
}
}
如果您有任何问题,请告诉我。
谢谢你,
索玛。