Проверка подлинности токена веб-API ASP Identity 2 + - постоянные утверждения не загружаются
У меня возникли проблемы с утверждениями в ASP.NET Web API Token Auth.
По сути, я создал пользователя с некоторыми утверждениями (значения хранятся в таблице AspNetUserClaim), но когда создается удостоверение пользователя, эти утверждения не извлекаются из базы данных.
Разбивка моей установки выглядит следующим образом.
Пользовательский класс: имеет метод GenerateUserIdentityAsync (довольно стандартный) и несколько пользовательских свойств:
public class LibraryUser : IdentityUser{ //Add Custom Properties Here public string Company { get; set; } public string DisplayName { get; set; } public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<LibraryUser> manager, string authenticationType) { // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType var userIdentity = await manager.CreateIdentityAsync(this, authenticationType); // Add custom user claims here return userIdentity; } }
Мой DBContext объявляет некоторые простые изменения имени, чтобы БД выглядела лучше
protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // Modify the Model creation properties.. modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); //Rename Identity 2.0 Tables to something nicer.. modelBuilder.Entity<LibraryUser>().ToTable("LibraryUser"); modelBuilder.Entity<IdentityUser>().ToTable("LibraryUser"); modelBuilder.Entity<IdentityRole>().ToTable("Role"); modelBuilder.Entity<IdentityUserRole>().ToTable("UserRole"); modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaim"); modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogin"); }
У меня есть класс Simple UserManager с именем LibraryUserManager, который просто расширяет UserManager для моего типа пользователя.
public class LibraryUserManager : UserManager<LibraryUser>
Когда база данных заполнена (при вызове Update-Database), создается следующий пользователь:
// -- Create Admin User, put in admin role.. LibraryUserManager userManager = new LibraryUserManager(new UserStore<LibraryUser>(context)); var user = new LibraryUser() { UserName = "admin@admin.com", Email = "admin@admin.com", DisplayName = "Administrator", Company = "Test" }; userManager.Create(user, "Password1."); userManager.AddClaim(user.Id, new Claim(ClaimTypes.Role, "user")); userManager.AddClaim(user.Id, new Claim(ClaimTypes.Role, "author")); userManager.AddClaim(user.Id, new Claim(ClaimTypes.Role, "reviewer")); userManager.AddClaim(user.Id, new Claim(ClaimTypes.Role, "admin"));
Как только это будет выполнено.. в базе данных есть пользователь (в таблице LibraryUser) и утверждения (в таблице UserClaim)
- Когда пользователь проходит проверку подлинности с помощью моего пользовательского поставщика проверки подлинности, он обнаруживается (через диспетчер пользователей) и вызывается GenerateUserIdentityAsync:
РЕДАКТИРОВАТЬ: показывая остальную часть этого метода...
var userManager = context.OwinContext.GetUserManager<LibraryUserManager>();
LibraryUser user = await userManager.FindAsync(context.UserName, context.Password);
//check if a user exists
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, OAuthDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName, user.DisplayName, oAuthIdentity);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
Содержимое создаваемых свойств (названных выше):
public static AuthenticationProperties CreateProperties(string userName, string displayName, ClaimsIdentity oAuthIdentity) { IDictionary<string, string> data = new Dictionary<string, string> { { "userName", userName }, { "displayName", displayName }, { "roles", string.Join(",", oAuthIdentity.Claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray())} }; return new AuthenticationProperties(data); }
Когда пользователь авторизован.. Я установил точку останова в LibraryUser.GenerateUserIdentityAsync (код по пункту 1 выше), и единственными утверждениями в коллекции ClaimsIdentity.Claims, возвращенными CreateIdentityAsync, являются стандартные (name, identity_provider, security_stamp и еще один)..... претензии, которые я добавил вручную, не возвращаются из БД..
Кто-нибудь может увидеть, что мне не хватает??
Я постарался предоставить всю информацию, которую могу, если вам потребуется больше комментариев, пожалуйста, и я исправлю свой вопрос.
Заранее спасибо
_L
2 ответа
Конфликтующая строка находится внутри метода OnModelCreating:
modelBuilder.Entity<LibraryUser>().ToTable("LibraryUser");
modelBuilder.Entity<IdentityUser>().ToTable("LibraryUser"); // <-- this one
Поскольку вы используете LibraryUser как производный класс от IdentityUser, вам не нужно явно отображать IdentityUser в таблицу. Это мешает созданию первичного и внешнего ключей в базе данных.
Претензии для размещения в базе данных (вы сделали в AddClaim()
) и сделать в токене разные. Вы должны поместить данные претензии вручную в унаследованный OAuthAuthorizationServerProvider
класс, который ASP.NET предоставляет по умолчанию ApplicatoinOAuthProvider.cs в папке "Provider" или в любом другом провайдере oauth.
Там переопределить GrantResourceOwnerCredentials()
метод сделал AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
для того, чтобы положить претензии в токене.
Затем Windows Identity будет считывать утверждения из поставленного токена.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
using (var userManager = _container.GetInstance<ApplicationUserManager>())
{
var 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 userManager.CreateIdentityAsync(user,
context.Options.AuthenticationType);
ClaimsIdentity cookiesIdentity = await userManager.CreateIdentityAsync(user,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user);
// Below line adds additional claims in token.
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
}
public static AuthenticationProperties CreateProperties(AspNetUser user)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{"Id", user.Id.ToString(CultureInfo.InvariantCulture)},
{"http://axschema.org/namePerson", user.Nickname,},
{"http://axschema.org/contact/email", user.Email,},
};
return new AuthenticationProperties(data);
}