Подтвердить что ты не робот

DB-первая путаница аутентификации с ASP.NET Web API 2 + EF6

Мне нужно создать приложение Web API С# для существующей базы данных MySQL. Мне удалось использовать Entity Framework 6 для привязки каждой таблицы базы данных к RESTful API (который позволяет выполнять операции CRUD).

Я хочу внедрить систему регистрации/регистрации (чтобы я мог выполнять роли и разрешения в будущем и ограничивать определенные запросы API).

В базе данных MySQL, которую я должен использовать, есть таблица для пользователей (называемая user), которая содержит следующие пояснительные столбцы:

  • id
  • email
  • username
  • password_hash

Похоже, что де-факто стандартом аутентификации является ASP.Net Identity. Я провел последний час, пытаясь выяснить, как сделать работу Identity с существующей настройкой DB-First Entity Framework.

Если я попытаюсь построить ApplicationUser экземпляры, хранящие экземпляры user (объекты из базы данных MySQL) для извлечения пользовательских данных, я получаю следующую ошибку:

Тип объекта ApplicationUser не является частью модели для текущего контекста.

Я предполагаю, что мне нужно хранить данные Identity в моей базе данных MySQL, но не могу найти какой-либо ресурс о том, как это сделать. Я попытался полностью удалить класс ApplicationUser и сделать мой класс user сущностью из IdentityUser, но вызов UserManager.CreateAsync привел к ошибкам преобразования LINQ to Entities.

Как настроить аутентификацию в приложении Web API 2, имеющем существующий объект user?

4b9b3361

Ответ 1

Вы говорите:

Я хочу внедрить систему регистрации/регистрации (чтобы я мог выполнять роли и разрешения в будущем и ограничивать определенные API).

Как настроить аутентификацию в приложении Web API 2, имея существующий пользовательский объект?

Это определенно означает, что вам требуется НЕ идентификатор ASP.NET. ASP.NET Identity - это технология обработки всех продуктов пользователей. Он фактически не "делает" механизм аутентификации. Идентификатор ASP.NET использует механизм аутентификации OWIN, что является другой вещью.

То, что вы ищете, не , как использовать идентификатор ASP.NET с моей существующей таблицей ", но ". Как настроить аутентификацию OWIN с помощью моей таблицы "Существующие пользователи"

Чтобы использовать OWIN Auth, выполните следующие действия:

Установите пакеты:

Owin
Microsoft.AspNet.Cors
Microsoft.AspNet.WebApi.Client
Microsoft.AspNet.WebApi.Core
Microsoft.AspNet.WebApi.Owin
Microsoft.AspNet.WebApi.WebHost
Microsoft.Owin
Microsoft.Owin.Host.SystemWeb
Microsoft.Owin.Security
Microsoft.Owin.Security.OAuth

Создайте файл Startup.cs внутри корневой папки (пример):

убедитесь, что [сборка: OwinStartup] настроена правильно

[assembly: OwinStartup(typeof(YourProject.Startup))]
namespace YourProject
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var config = new HttpConfiguration();
            //other configurations

            ConfigureOAuth(app);
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            app.UseWebApi(config);
        }

        public void ConfigureOAuth(IAppBuilder app)
        {
            var oAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/api/security/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromHours(2),
                Provider = new AuthorizationServerProvider()
            };

            app.UseOAuthAuthorizationServer(oAuthServerOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }
    }

    public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

            try
            {
                //retrieve your user from database. ex:
                var user = await userService.Authenticate(context.UserName, context.Password);

                var identity = new ClaimsIdentity(context.Options.AuthenticationType);

                identity.AddClaim(new Claim(ClaimTypes.Name, user.Name));
                identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));

                //roles example
                var rolesTechnicalNamesUser = new List<string>();

                if (user.Roles != null)
                {
                    rolesTechnicalNamesUser = user.Roles.Select(x => x.TechnicalName).ToList();

                    foreach (var role in user.Roles)
                        identity.AddClaim(new Claim(ClaimTypes.Role, role.TechnicalName));
                }

                var principal = new GenericPrincipal(identity, rolesTechnicalNamesUser.ToArray());

                Thread.CurrentPrincipal = principal;

                context.Validated(identity);
            }
            catch (Exception ex)
            {
                context.SetError("invalid_grant", "message");
            }
        }
    }
}

Используйте атрибут [Authorize] для авторизации действий.

Вызовите api/security/token с помощью GrantType, UserName и Password, чтобы получить токен-носитель. Вот так:

"grant_type=password&username=" + username + "&password=" password;

Отправьте токен в HttpHeader Authorization как Bearer "YOURTOKENHERE". Вот так:

headers: { 'Authorization': 'Bearer ' + token }

Надеюсь, что это поможет!

Ответ 2

Поскольку ваша схема БД несовместима со значением по умолчанию UserStore, вы должны реализовать свои собственные классы UserStore и UserPasswordStore, а затем ввести их в UserManager. Рассмотрим этот простой пример:

Сначала напишите свой пользовательский класс и реализуйте интерфейс IUser:

class User:IUser<int>
{
    public int ID {get;set;}
    public string Username{get;set;}
    public string Password_hash {get;set;}
    // some other properties 
}

Теперь создайте свой собственный класс UserStore и IUserPasswordStore следующим образом:

public class MyUserStore : IUserStore<User>, IUserPasswordStore<User>
{
    private readonly MyDbContext _context;

    public MyUserStore(MyDbContext context)
    {
        _context=context;
    }

    public Task CreateAsync(AppUser user)
    {
        // implement your desired logic such as
        // _context.Users.Add(user);
    }

    public Task DeleteAsync(AppUser user)
    {
        // implement your desired logic
    }

    public Task<AppUser> FindByIdAsync(string userId)
    {
        // implement your desired logic
    }

    public Task<AppUser> FindByNameAsync(string userName)
    {
        // implement your desired logic
    }

    public Task UpdateAsync(AppUser user)
    {
        // implement your desired logic
    }

    public void Dispose()
    {
        // implement your desired logic
    }

    // Following 3 methods are needed for IUserPasswordStore
    public Task<string> GetPasswordHashAsync(AppUser user)
    {
        // something like this:
        return Task.FromResult(user.Password_hash);
    }

    public Task<bool> HasPasswordAsync(AppUser user)
    {
        return Task.FromResult(user.Password_hash != null);
    }

    public Task SetPasswordHashAsync(AppUser user, string passwordHash)
    {
        user.Password_hash = passwordHash;
        return Task.FromResult(0);
    }
}

Теперь у вас есть собственное хранилище пользователей, просто вставьте его в менеджер пользователя:

public class ApplicationUserManager: UserManager<User, int>
{
    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
         var manager = new ApplicationUserManager(new MyUserStore(context.Get<MyDbContext>()));
         // rest of code
    }
}

Также обратите внимание, что вы должны непосредственно наследовать свой класс контекста DB из DbContext not IdentityDbContext, так как вы внедрили собственное хранилище пользователей.