管理用户密码更改

管理用户密码更改

本文介绍了OAuth 访问和刷新令牌控制/管理用户密码更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在开发内部移动应用程序和网络 API.我们正在使用带有 asp.net Identy 2 OAuth 的 asp.net web api 2.

We are in the process of developing a in house mobile application and web api.We are using asp.net web api 2 with asp.net Identy 2 OAuth.

我已经启动并运行了 api 并给了我一个不记名令牌.但是,我想将流程稍微修改为类似以下内容:

I have got the api up and running and giving me a bearer token. However I want to slightly modify the process flow to something like along the lines of this:

  1. 应用用户使用用户名和密码登录 api.
  2. 应用收到有效期为 30 天的刷新令牌.
  3. 然后应用程序请求访问令牌,为 api 提供刷新令牌.(在这里,如果用户更改了密码或帐户被锁定,我希望能够使请求无效).
  4. 应用获取一个访问令牌,有效期为 30 分钟,如果密码检查失败,它会收到 401.
  5. 应用可以在接下来的 29 分钟内使用给定的访问令牌访问 API.之后,应用程序必须使用刷新令牌获取新的访问令牌.

我想这样做的原因是为了阻止用户设备在更改密码后获得对 api 的访问权限.如果他们的手机被盗,他们需要能够登录网站并更改密码,以便手机的新所有者无法访问我们公司的服务.

Reason I want to do this is in order to stop a users devices gaining access to the api after they have changed their password. If their phone gets stolen they need to be able to login to the website and change their password so the new owner of the phone cannot gain access to our companies services.

我提出的解决方案是否可行,如果可行,这是一个明智的解决方案吗?我没有忘记任何关键要素?

Is my proposed solution do able, and if so is it a sensible solution? I haven't forgotten any crucial elements?

我愿意在每次令牌刷新时进行数据库访问,但不会在每次 API 调用时进行.

I am willing to do a db access on ever token refresh, but not on every API call.

总结一下我的问题是:

  1. 我计划的方法是否明智?
  2. 我如何安全地检查密码是否已更改或帐户是否在刷新令牌过程中被锁定.

请在下面找到我当前的 OAuth 设置和类:(我已尝试添加刷新令牌功能,但尚未尝试添加任何密码验证)

Please find my current OAuth Setups and classes below: (I have tried to add the refresh token functionality, but have not attempted to add any password verification yet)

Startup.Auth.cs

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

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

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);
    }
}

推荐答案

如果我理解你的任务是正确的,这里有一个想法.

If I understood your task right, here is an idea.

在创建访问令牌事件中,您可以检查密码是否已从网站更改,如果是,则撤销刷新令牌.(您可以创建一些标志,表明密码已更改或其他内容)

On the create access token event, you can check if the password has been changed from the website and if so, revoke the refresh token. (you can create some flag that the password has been changed or something)

在您创建访问令牌时不应该经常这样做,因此数据库访问应该没有问题.

It should not be often when you are creating an access token so there should be no problems with the db access.

现在的问题是如何撤销刷新令牌.除非有一种构建方式,否则您将不得不实施自定义方式.这里的一个想法是检查刷新令牌创建日期和更改密码操作的日期.如果在创建刷新令牌后进行更改密码操作,则不会对用户进行身份验证.

Now the question is how to revoke a refresh token. Unless there is a build in way you will have to implement a custom one. An idea here is to check the refresh token creation date and the date of the change password operation. If the change password operation is done after the creation of the refresh token, you do not authenticate the user.

告诉我你对此的看法.

这篇关于OAuth 访问和刷新令牌控制/管理用户密码更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-22 22:20