我们正在开发内部移动应用程序和web api。 我们正在使用asp.net web api 2和asp.net Identy 2 OAuth。
我已经启动并运行了api并给了我一个持票人令牌。但是,我想稍微修改一下这样的流程:
我想这样做的原因是为了阻止用户设备在更改密码后获得对api的访问权限。如果他们的手机被盗,他们需要能够登录网站并更改密码,以便手机的新主人无法访问我们公司的服务。
我建议的解决方案能否做到,如果是,这是一个明智的解决方案吗?我还没有忘记任何关键因素吗?
我愿意在令牌刷新时进行数据库访问,但不是每次API调用都会进行。
总结一下我的问题是:
请在下面找到我当前的OAuth设置和类:(我尝试添加刷新令牌功能,但尚未尝试添加任何密码验证)
Startup.Auth.cs
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);
}
ApplicationRefreshTokenProvider.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);
}
}
ApplicationOAuthProvider.cs
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);
}
}
答案 0 :(得分:0)
如果我理解你的任务是正确的,这是一个想法。
在创建访问令牌事件上,您可以检查密码是否已从网站更改,如果是,则撤消刷新令牌。 (您可以创建一些密码已更改的标志或其他内容)
创建访问令牌时不应该经常这样,因此db访问应该没有问题。
现在的问题是如何撤销刷新令牌。除非有构建方式,否则您必须实现自定义构建。这里的想法是检查刷新令牌创建日期和更改密码操作的日期。如果在创建刷新令牌后完成更改密码操作,则不会对用户进行身份验证。
让我知道你对此的看法。