I can't find anyway to use AspIdentity classes and I couldn't find a way to implement custom classes too. Can anyone help me?
Thanks.
I believe if you implement IResourceOwnerPasswordValidator, then add it to DI that's all you need to do. In the ctor for your implementation pass in the the user store and then use something similar to var user = await UserManager.FindAsync(User.Identity.Name,VerifyViewModel.Password)
` public class AspNetIdentityResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
private readonly UserManager
public AspNetIdentityResourceOwnerPasswordValidator(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
async public Task<CustomGrantValidationResult> ValidateAsync(string userName, string password, ValidatedTokenRequest request)
{
var user = await _userManager.FindByNameAsync(userName);
if (user != null && await _userManager.CheckPasswordAsync(user, password))
return new CustomGrantValidationResult(user.Id, "password");
return new CustomGrantValidationResult("Invalid username or password");
}
}`
I believe you should also implement IProfileService.
public class AspNetIdentityProfileService : IProfileService
{
private readonly UserManager<IdentityUser> _userManager;
public AspNetIdentityProfileService(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
async public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var subject = context.Subject;
if (subject == null) throw new ArgumentNullException(nameof(context.Subject));
var subjectId = subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(subjectId);
if (user == null)
throw new ArgumentException("Invalid subject identifier");
var claims = await GetClaimsFromUser(user);
if (!context.AllClaimsRequested)
{
var requestedClaimTypes = context.RequestedClaimTypes;
if (requestedClaimTypes != null)
claims = claims.Where(c => requestedClaimTypes.Contains(c.Type));
else
claims = claims.Take(0);
}
context.IssuedClaims = claims;
}
async public Task IsActiveAsync(IsActiveContext context)
{
var subject = context.Subject;
if (subject == null) throw new ArgumentNullException(nameof(context.Subject));
var subjectId = subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(subjectId);
context.IsActive = false;
if (user != null)
{
if (_userManager.SupportsUserSecurityStamp)
{
var security_stamp = subject.Claims.Where(c => c.Type == "security_stamp").Select(c => c.Value).SingleOrDefault();
if (security_stamp != null)
{
var db_security_stamp = await _userManager.GetSecurityStampAsync(user);
if (db_security_stamp != security_stamp)
return;
}
}
context.IsActive =
!user.LockoutEnabled ||
!user.LockoutEnd.HasValue ||
user.LockoutEnd <= DateTime.Now;
}
}
async private Task<IEnumerable<Claim>> GetClaimsFromUser(IdentityUser user)
{
var claims = new List<Claim>
{
new Claim(JwtClaimTypes.Subject, user.Id),
new Claim(JwtClaimTypes.PreferredUserName, user.UserName)
};
if (_userManager.SupportsUserEmail)
{
claims.AddRange(new[]
{
new Claim(JwtClaimTypes.Email, user.Email),
new Claim(JwtClaimTypes.EmailVerified, user.EmailConfirmed ? "true" : "false", ClaimValueTypes.Boolean)
});
}
if (_userManager.SupportsUserPhoneNumber && !string.IsNullOrWhiteSpace(user.PhoneNumber))
{
claims.AddRange(new[]
{
new Claim(JwtClaimTypes.PhoneNumber, user.PhoneNumber),
new Claim(JwtClaimTypes.PhoneNumberVerified, user.PhoneNumberConfirmed ? "true" : "false", ClaimValueTypes.Boolean)
});
}
if (_userManager.SupportsUserClaim)
{
claims.AddRange(await _userManager.GetClaimsAsync(user));
}
if (_userManager.SupportsUserRole)
{
var roles = await _userManager.GetRolesAsync(user);
claims.AddRange(roles.Select(role => new Claim(JwtClaimTypes.Role, role)));
}
return claims;
}
}
Disclaimer I found this code somewhere else, it's not my own.
Thanks for sharing. In the startup.cs, should I use service.addidentity and app.useidentity() along with app.useidentityserver()?
AddIdentity, AddIdentityServer and UseIdentityServer. I don't think you need to add Identity (UseIdentity) to the pipeline.
hmm, if I don't add that, the usermanager and signinmanager from aspidentity isn't working. is there anything I missed out?
services.AddIdentity() adds the services required from Identity to the DI container. With that should should be able to use it in Controllers or any class you need. What exactly isn't working?
I got this error...
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNet.Identity.IUserStore`1[Microsoft.AspNet.Identity.EntityFramework.IdentityUser]' while attempting to activate 'Microsoft.AspNet.Identity.UserManager`1[Microsoft.AspNet.Identity.EntityFramework.IdentityUser]'.
Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites(ServiceProvider provider, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
Following is my code for startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Extensions.PlatformAbstractions;
using System.IO;
using TEST_02_01.Configuration;
using TEST_02_01.Extensions;
using Microsoft.AspNet.Identity.EntityFramework;
using IdentityServer4.Core.Services;
using TEST_02_01.Services;
namespace TEST_02_01
{
public class Startup
{
private readonly IApplicationEnvironment _environment;
public IConfigurationRoot Configuration { get; set; }
public Startup(IHostingEnvironment env, IApplicationEnvironment environment)
{
_environment = environment;
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
if (env.IsDevelopment())
{
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
Configuration = builder.Build();
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var cert = new X509Certificate2(Path.Combine(_environment.ApplicationBasePath, "idsrv4test.pfx"), "idsrv3test");
var builder = services.AddIdentityServer(options =>
{
options.SigningCertificate = cert;
});
builder.AddInMemoryClients(Clients.Get());
builder.AddInMemoryScopes(Scopes.Get());
services.AddIdentity<IdentityUser, IdentityRole>();
builder.AddCustomGrantValidator<CustomGrantValidator>();
services
.AddMvc()
.AddRazorOptions(razor =>
{
razor.ViewLocationExpanders.Add(new TEST_02_01.UI.CustomViewLocationExpander());
});
services.AddTransient<TEST_02_01.UI.Login.LoginService>();
services.AddTransient<IProfileService, ProfileService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(LogLevel.Verbose);
loggerFactory.AddDebug(LogLevel.Verbose);
app.UseDeveloperExceptionPage();
app.UseIISPlatformHandler();
app.UseIdentityServer();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
It's because you are also using entity framework. You need to add the services for that. Check the sample. https://github.com/aspnet/Identity/blob/dev/samples/IdentitySample.Mvc/Startup.cs
sorry ya, with AddIdentity, UseIdentity and UseIdentityServer. will this conflict with IdentityServer?
I'm trying out with TheRubble's code, but the IdentityUser requires AspIdentity's EF's IdentityUser. did I make it wrongly?
Just add the services, don't add Identity to the pipeline. I don't think they conflict, but you will have 2 separate middleware doing cookie authentication.
The thing is UserManager expects an IUserStore. EF provides an implementation for this, or you could provide your own. So if you want to keep using EF just add entity framework stores (you will need to provide a dbcontext). If you want to build your own user store you can, just be aware that user manager assumes this is a fat class, and that it implements other interfaces.
Thanks buddy, let me try it out again. I actually simply would like to make use of aspidentity's db.. hope I can figure it out with your further helps :)
Now I code up the ProfileService, LoginService with userManager and signInManager.
I found that if not using app.UseIdentity() to the pipeline, it will throw me following error.
An unhandled exception occurred while processing the request.
InvalidOperationException: No authentication handler is configured to handle the scheme: Microsoft.AspNet.Identity.Application
Microsoft.AspNet.Http.Authentication.Internal.DefaultAuthenticationManager.<SignInAsync>d__13.MoveNext()
if I added Useidentity(), it works, but when it comes to sign out, users has to sign out separately from client app and idserver itself.
see my personal project RigoFunc.IdentityServer
@xyting I knew your project wouldn't be there, I KNEW IT!!!!
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Disclaimer I found this code somewhere else, it's not my own.