Oauth 2.0 用户密码更改时OAuth访问和刷新令牌控制/管理
我们正在开发内部移动应用程序和web api。 我们将asp.net web api 2与asp.net Identity 2 OAuth一起使用 我已经启动并运行了api,并给了我一个承载令牌。但是,我想稍微修改流程,使其类似于以下内容:Oauth 2.0 用户密码更改时OAuth访问和刷新令牌控制/管理,oauth-2.0,authorization,asp.net-web-api2,access-token,asp.net-identity-2,Oauth 2.0,Authorization,Asp.net Web Api2,Access Token,Asp.net Identity 2,我们正在开发内部移动应用程序和web api。 我们将asp.net web api 2与asp.net Identity 2 OAuth一起使用 我已经启动并运行了api,并给了我一个承载令牌。但是,我想稍微修改流程,使其类似于以下内容: 应用程序用户使用用户名和密码登录到api 应用程序收到有效期为30天的刷新令牌 然后,应用程序请求一个访问令牌,为api提供刷新令牌。(在这里,如果用户更改了密码或帐户被锁定,我希望能够使请求无效) 应用程序获取30分钟内有效的访问令牌,或者如果密码检查失败
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(IdentityDbContext.Create);
app.CreatePerOwinContext<FskUserManager>(FskUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
RefreshTokenProvider = new ApplicationRefreshTokenProvider(),
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
ApplicationAuthProvider.cs
public class ApplicationRefreshTokenProvider : AuthenticationTokenProvider
{
public override void Create(AuthenticationTokenCreateContext context)
{
// Expiration time in minutes
int refreshTokenExpiration = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["ApiRefreshTokenExpiry"]);
context.Ticket.Properties.ExpiresUtc = new DateTimeOffset(DateTime.Now.AddMinutes(refreshTokenExpiration));
context.SetToken(context.SerializeTicket());
}
public override void Receive(AuthenticationTokenReceiveContext context)
{
context.DeserializeTicket(context.Token);
}
}
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
public ApplicationOAuthProvider(string publicClientId)
{
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<FskUserManager>();
FskUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == _publicClientId)
{
Uri expectedRootUri = new Uri(context.Request.Uri, "/");
if (expectedRootUri.AbsoluteUri == context.RedirectUri)
{
context.Validated();
}
}
return Task.FromResult<object>(null);
}
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
}
公共类ApplicationAuthProvider:OAuthAuthorizationServerProvider
{
私有只读字符串_publicClientId;
公共ApplicationAuthProvider(字符串publicClientId)
{
if(publicClientId==null)
{
抛出新ArgumentNullException(“publicClientId”);
}
_publicClientId=publicClientId;
}
公共重写异步任务GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentials上下文)
{
var userManager=context.OwinContext.GetUserManager();
FskUser user=await userManager.FindAsync(context.UserName,context.Password);
if(user==null)
{
SetError(“无效的授权”,“用户名或密码不正确”);
返回;
}
ClaimsIdentity oAuthIdentity=等待用户.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimSideEntity cookiesIdentity=等待用户.GenerateUserIdentity异步(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties=CreateProperties(user.UserName);
AuthenticationTicket=新的AuthenticationTicket(OAuthidentitity,属性);
上下文。已验证(票证);
context.Request.context.Authentication.sign(cookiesIdentity);
}
公共重写任务令牌端点(OAuthTokenEndpointContext)
{
foreach(context.Properties.Dictionary中的KeyValuePair属性)
{
AdditionalResponseParameters.Add(property.Key,property.Value);
}
返回Task.FromResult(空);
}
公共覆盖任务ValidateClientAuthentication(OAuthValidateClientAuthenticationContext)
{
//资源所有者密码凭据不提供客户端ID。
if(context.ClientId==null)
{
context.Validated();
}
返回Task.FromResult(空);
}
公共覆盖任务ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext上下文)
{
if(context.ClientId==\u publicClientId)
{
Uri expectedRootUri=新Uri(context.Request.Uri,“/”;
if(expectedRootUri.AbsoluteUri==context.RedirectUri)
{
context.Validated();
}
}
返回Task.FromResult(空);
}
公共静态身份验证属性CreateProperties(字符串用户名)
{
IDictionary data=新字典
{
{“用户名”,用户名}
};
返回新的AuthenticationProperties(数据);
}
}
如果我正确理解了您的任务,下面是一个想法
在“创建访问令牌”事件中,您可以检查是否已从网站更改密码,如果已更改,请撤消刷新令牌。(您可以创建密码已更改的标志或其他标志)
在创建访问令牌时不应该经常这样做,所以db访问应该不会出现问题
现在的问题是如何撤销刷新令牌。除非有内置方式,否则您必须实现自定义方式。这里的一个想法是检查刷新令牌创建日期和更改密码操作的日期。如果更改密码操作是在创建刷新令牌后完成的,则不会对用户进行身份验证
请告诉我您对此的看法。据我所知,没有办法恢复代币。据我所知,发行的代币有效期与到期日相同。我正在寻找一个关于如何实际实施它的更技术性的答案。我在哪里覆盖tke令牌生成逻辑等。您找到这个问题的答案了吗?解决方案是什么?我最终提出了一个解决方案,我最终不得不自定义它并将令牌存储在数据库中?