Оновлення - IdentityServer 4 змінив та замінив IUserService на IResourceOwnerPasswordValidator та IProfileService
Я використовував свій UserRepository для отримання всіх даних користувача з бази даних. Це вводиться (DI) в конструктори і визначається в Startup.cs
. Я також створив наступні класи для сервера ідентифікації (який також вводиться):
Спочатку визначте ResourceOwnerPasswordValidator.cs
:
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
private readonly IUserRepository _userRepository;
public ResourceOwnerPasswordValidator(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
try
{
var user = await _userRepository.FindAsync(context.UserName);
if (user != null)
{
if (user.Password == context.Password) {
context.Result = new GrantValidationResult(
subject: user.UserId.ToString(),
authenticationMethod: "custom",
claims: GetUserClaims(user));
return;
}
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "Incorrect password");
return;
}
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "User does not exist.");
return;
}
catch (Exception ex)
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "Invalid username or password");
}
}
public static Claim[] GetUserClaims(User user)
{
return new Claim[]
{
new Claim("user_id", user.UserId.ToString() ?? ""),
new Claim(JwtClaimTypes.Name, (!string.IsNullOrEmpty(user.Firstname) && !string.IsNullOrEmpty(user.Lastname)) ? (user.Firstname + " " + user.Lastname) : ""),
new Claim(JwtClaimTypes.GivenName, user.Firstname ?? ""),
new Claim(JwtClaimTypes.FamilyName, user.Lastname ?? ""),
new Claim(JwtClaimTypes.Email, user.Email ?? ""),
new Claim("some_claim_you_want_to_see", user.Some_Data_From_User ?? ""),
new Claim(JwtClaimTypes.Role, user.Role)
};
}
І ProfileService.cs
:
public class ProfileService : IProfileService
{
private readonly IUserRepository _userRepository;
public ProfileService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
try
{
if (!string.IsNullOrEmpty(context.Subject.Identity.Name))
{
var user = await _userRepository.FindAsync(context.Subject.Identity.Name);
if (user != null)
{
var claims = GetUserClaims(user);
context.IssuedClaims = claims.Where(x => context.RequestedClaimTypes.Contains(x.Type)).ToList();
}
}
else
{
var userId = context.Subject.Claims.FirstOrDefault(x => x.Type == "sub");
if (!string.IsNullOrEmpty(userId?.Value) && long.Parse(userId.Value) > 0)
{
var user = await _userRepository.FindAsync(long.Parse(userId.Value));
if (user != null)
{
var claims = ResourceOwnerPasswordValidator.GetUserClaims(user);
context.IssuedClaims = claims.Where(x => context.RequestedClaimTypes.Contains(x.Type)).ToList();
}
}
}
}
catch (Exception ex)
{
}
}
public async Task IsActiveAsync(IsActiveContext context)
{
try
{
var userId = context.Subject.Claims.FirstOrDefault(x => x.Type == "user_id");
if (!string.IsNullOrEmpty(userId?.Value) && long.Parse(userId.Value) > 0)
{
var user = await _userRepository.FindAsync(long.Parse(userId.Value));
if (user != null)
{
if (user.IsActive)
{
context.IsActive = user.IsActive;
}
}
}
}
catch (Exception ex)
{
}
}
}
Потім Startup.cs
я зробив наступне:
public void ConfigureServices(IServiceCollection services)
{
var cert = new X509Certificate2(Path.Combine(_environment.ContentRootPath, "idsrv4test.pfx"), "your_cert_password");
services.AddScoped(_ => new YourDbContext(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IUserRepository, UserRepository>();
services.AddIdentityServer()
.AddSigningCredential(cert)
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddProfileService<ProfileService>();
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
services.AddTransient<IProfileService, ProfileService>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseIdentityServer();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
IdentityServerAuthenticationOptions identityServerValidationOptions = new IdentityServerAuthenticationOptions
{
Authority = "http://localhost:50000/",
ApiSecret = "secret",
ApiName = "my.api.resource",
AutomaticAuthenticate = true,
SupportedTokens = SupportedTokens.Both,
AutomaticChallenge = true,
RequireHttpsMetadata = false
};
app.UseIdentityServerAuthentication(identityServerValidationOptions);
}
Вам також знадобиться, Config.cs
що визначає ваших клієнтів, API та ресурси. Приклад можна знайти тут: https://github.com/IdentityServer/IdentityServer4.Demo/blob/master/src/IdentityServer4Demo/Config.cs
Тепер ви можете мати можливість викликати IdentityServer / connect / token

Для отримання додаткової інформації перегляньте документацію: https://media.readthedocs.org/pdf/identityserver4/release/identityserver4.pdf
Стара відповідь (це більше не працює для нових IdentityServer4)
Це досить просто, як тільки ти зрозумієш потік речей.
Налаштуйте службу IdentityService таким чином (у Startup.cs - ConfigureServices()
):
var builder = services.AddIdentityServer(options =>
{
options.SigningCertificate = cert;
});
builder.AddInMemoryClients(Clients.Get());
builder.AddInMemoryScopes(Scopes.Get());
builder.Services.AddTransient<IUserService, UserService>();
services.AddTransient<IUserRepository, UserRepository>();
Потім налаштуйте UserService
public class UserService : IUserService
{
private IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public Task AuthenticateLocalAsync(LocalAuthenticationContext context)
{
var user = _userRepository.Find(context.UserName);
if (user.Password == context.Password)
{
context.AuthenticateResult = new AuthenticateResult(
user.UserId.ToString(),
user.Email,
new Claim[]
{
new Claim(Constants.ClaimTypes.Name, user.Firstname + " " + user.Surname),
new Claim(Constants.ClaimTypes.Email, user.Email),
new Claim(Constants.ClaimTypes.Role, user.Role.ToString()),
new Claim("company", user.Company)
}
);
}
return Task.FromResult(0);
}
public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var user = _userRepository.Find(context.Subject.Identity.Name);
if (user != null)
{
var claims = new Claim[]
{
new Claim(Constants.ClaimTypes.Name, user.Firstname + " " + user.Surname),
new Claim(Constants.ClaimTypes.Email, user.Email),
new Claim(Constants.ClaimTypes.Role, user.Role.ToString(), ClaimValueTypes.Integer),
new Claim("company", user.Company)
};
context.IssuedClaims = claims.Where(x => context.RequestedClaimTypes.Contains(x.Type));
}
return Task.FromResult(0);
}
public Task IsActiveAsync(IsActiveContext context)
{
var user = _userRepository.Find(context.Subject.Identity.Name);
return Task.FromResult(user != null);
}
}
В основному, вводячи UserService
в builder
(типу IdentityServerBuilder
) Services
, дозволяє йому викликати UserService на auth.
Сподіваюся, це допомагає іншим, оскільки мені це зайняло пару годин.
IUserService
на IdSvr4 (для ASP.NET Core 1.0) більше не існує. Він був замінений двома інтерфейсами / сервісамиIProfileService
таIResourceOwnerPasswordValidator
.