Base solution for your next web application
Open Closed

How to implement IUserTokenProvider, for usermanager #1033


User avatar
0
zana created

I need to GenerateEmailConfirmationTokenAsync, and must implement IUserTokenProvider. I drive class UserManager : AbpUserManager<Tenant, Role, User>, IUserTokenProvider<User, long>

implememted the interface public Task<string> GenerateAsync(string purpose, UserManager<User, long> manager, User user) { Guid resetToken = Guid.NewGuid(); user.PasswordResetToken = resetToken; manager.UpdateAsync(user); return Task.FromResult<string>(resetToken.ToString()); }

    public Task&lt;bool&gt; IsValidProviderForUserAsync(UserManager&lt;User, long&gt; manager, User user)
    {
        if (manager == null) throw new ArgumentNullException();
        else
        {
            return Task.FromResult&lt;bool&gt;(manager.SupportsUserPassword);
        }
    }

    public Task NotifyAsync(string token, UserManager&lt;User, long&gt; manager, User user)
    {

        return Task.FromResult&lt;int&gt;(0);
    }

    public Task&lt;bool&gt; ValidateAsync(string purpose, string token, UserManager&lt;User, long&gt; manager, User user)
    {
        return Task.FromResult&lt;bool&gt;(user.PasswordResetToken.ToString() == token);
    }

added a property PasswordResetToken to User : AbpUser<Tenant, User>

But get Error, DbContext' context has changed since the database was created. Could you explain how to implement IUserTokenProvider, for usermanager


9 Answer(s)
  • User Avatar
    0
    hikalkan created
    Support Team

    It seems that you changed User entity and you need to add code first migration. Did you try "add-migration" command?

  • User Avatar
    0
    zana created

    yes, I changed User entity and added Add-Migration ...and update-database -verbos... updated database wirh update-database -verbos... , its woriking now but get Error for this statement:

    var pass = _userManager.ResetPassword(user.Id, resetToken.ToString(), new PasswordHasher().HashPassword("1q2w3e4r"));

    the error is No IUserTokenProvider is registered.

  • User Avatar
    0
    zana created

    now it works <a class="postlink" href="http://stackoverflow.com/questions/22629936/no-iusertokenprovider-is-registered">http://stackoverflow.com/questions/2262 ... registered</a>

    UserManager.UserTokenProvider = new DataProtectorTokenProvider<User, long>(provider.Create("EmailConfirmation")) as IUserTokenProvider<User, long>; var code = await _userManager.GenerateEmailConfirmationTokenAsync(user.Id);

  • User Avatar
    0
    tinman created

    For hosting on Azure websites, the DpapiDataProtectionProvider cannot be used.

    Taken from this source: [http://goo.gl/ScdYP5])

    Here is the solution that worked for me in ABP:

    Added to Startup.cs

    //Global
     internal static IDataProtectionProvider DataProtectionProvider { get; private set; }
    

    Added to Configuration

    public void Configuration(IAppBuilder app)
            {
                 ...
                 DataProtectionProvider = app.GetDataProtectionProvider();
             }
    

    Instantiated in Account Controller :

    var dataProtectionProvider = Startup.DataProtectionProvider;
     _userManager.UserTokenProvider = new DataProtectorTokenProvider<User, long>(dataProtectionProvider.Create("ASP.NET Identity")) as IUserTokenProvider<User, long>;
    
    var resetcode = await _userManager.GeneratePasswordResetTokenAsync(user.Id);
    var emailcode = await _userManager.GenerateEmailConfirmationTokenAsync(user.Id);
    //use either token as needed 
    ...
    
  • User Avatar
    0
    djfuzzy created

    Is it possible to have this logic in the Application layer? I would much rather have the email confirmation tokens being generated there then having clients do it.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    @TInman, thanks a lot for your solution, it is really helpful. @djfuzzy, I think you can gneerate tokens in the application layer, because you can use UserManager in application layer. But you need to set userManager's UserTokenProvider in web layer (probably in your web module).

  • User Avatar
    0
    djfuzzy created

    <cite>ismcagdas: </cite> @djfuzzy, I think you can gneerate tokens in the application layer, because you can use UserManager in application layer. But you need to set userManager's UserTokenProvider in web layer (probably in your web module).

    How would this work for clients of the Web API? It sounds like having the Application layer being dependent on the Web layer defies the SOLID principles of programming. I don't want to have each client having to generate the token.

  • User Avatar
    0
    hikalkan created
    Support Team

    Hi @difuzzy,

    What do you mean by clients of Web API? Browsers, mobile apps.. which calls Web API services remotely. If so, no problem, token provider will be valid since it's assigned in Web/WebApi layer, in Startup class: <a class="postlink" href="https://github.com/aspnetzero/aspnet-zero/blob/dev/src/MyCompanyName.AbpZeroTemplate.Web/App_Start/Startup.cs#L43">https://github.com/aspnetzero/aspnet-ze ... tup.cs#L43</a>

    Beside that, if you worry about "good layering", you're right. Because, if you develop a Desktop application and want to use application layer (and don't use web/webapi layer), then tokenprovider will not be defined and you will get exception if you generate password reset token using UserManager.GeneratePasswordResetTokenAsync. That means, a functionality in application layer, indirectly depends on the web layer and it has not a built-in fallback mechanism (to allow work without web layer).

    Why we did it like that? Because this is the most common way of getting a valid data protection validator, OWIN provides it to us. We haven't searched for another solution.

    So, it's actually not a problem for you, but if you care about it, please create an issue here and we search for a better way: <a class="postlink" href="https://github.com/aspnetboilerplate/module-zero/issues/new">https://github.com/aspnetboilerplate/mo ... issues/new</a>

    Thanks a lot.

  • User Avatar
    0
    djfuzzy created

    <cite>hikalkan: </cite> Hi @difuzzy,

    What do you mean by clients of Web API? Browsers, mobile apps.. which calls Web API services remotely. If so, no problem, token provider will be valid since it's assigned in Web/WebApi layer, in Startup class: <a class="postlink" href="https://github.com/aspnetzero/aspnet-zero/blob/dev/src/MyCompanyName.AbpZeroTemplate.Web/App_Start/Startup.cs#L43">https://github.com/aspnetzero/aspnet-ze ... tup.cs#L43</a>

    Beside that, if you worry about "good layering", you're right. Because, if you develop a Desktop application and want to use application layer (and don't use web/webapi layer), then tokenprovider will not be defined and you will get exception if you generate password reset token using UserManager.GeneratePasswordResetTokenAsync. That means, a functionality in application layer, indirectly depends on the web layer and it has not a built-in fallback mechanism (to allow work without web layer).

    Why we did it like that? Because this is the most common way of getting a valid data protection validator, OWIN provides it to us. We haven't searched for another solution.

    So, it's actually not a problem for you, but if you care about it, please create an issue here and we search for a better way: <a class="postlink" href="https://github.com/aspnetboilerplate/module-zero/issues/new">https://github.com/aspnetboilerplate/mo ... issues/new</a>

    Thanks a lot.

    No that all makes sense. You're right, I should be able to generate a token in WebAPI. I should be good to go. Thanks!