Заполнение данных и создание/управление ролями в MVC4 — насколько это сложно?

Я собираюсь сойти с ума, поэтому я еще раз попытаюсь получить помощь... Я использую Visual Studio Express 2012 для Интернета, чтобы создать интернет-проект с использованием C# + MVC4 + Razor + Entity Framework + ASP.NET 4.5. Мне нужно сделать следующее: автоматически создать пользователя «admin» (который будет авторизован на всем сайте), а затем создать несколько ролей пользователей. Я читал о SimpleMembership, ролях и обо всем этом во всем Интернете, но, похоже, ничто не дает мне простого метода заставить все это работать.

Вот что я сделал до сих пор:

1- Создал класс DataContext:

public class DataContext : DbContext
{
public DataContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
}

2- Создал класс инициализатора, который, как я полагаю, даст мне пользователя-администратора и созданную роль администратора:

public class DataContextDbInitializer : DropCreateDatabaseAlways<DataContext>
{
protected override void Seed(DataContext context)
{
var roles = (Webmatrix.WebData.SimpleRoleProvider)System.Web.Security.Roles.Provider;
var membership = (Webmatrix.WebData.SimpleMembershipProvider)System.Web.Security.Membership.Provider;
if (!roles.RoleExists("Admins")) {
roles.CreateRole("Admins");
}
if (membership.GetUser("admin", false) == null) {
membership.CreateUserAndAccount("admin", "123456");
}
if (!roles.GetRolesForUser("admin").Contains("Admins")) {
roles.AddUsersToRoles(new[] { "admin" }, new[] { "Admins" });
} 
}
}

(Я пробовал наследовать от DropCreateDatabaseIfModelChanges, но это не помогает).

3- В метод App_Start в Global.asax добавлены две строки:

WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
Database.SetInitializer<DataContext>(new DataContextDbInitializer());

Я также пытался использовать WebSecurity.InitializeDatabaseConnection в методе Seed в моем классе DataContextDbInitializer, но это не сработало.

4- Удалена аннотация [InitializeSimpleMembership] из AccountController, поэтому я могу инициализировать его с самого начала жизненного цикла приложения (используя WebSecurity.InitializeDatabaseConnection в App_Start, как я объяснил в пункте 3) . Я попытался добавить [InitializeSimpleMembership] поверх метода Index в HomeController и удалить WebSecurity.InitializeDatabaseConnection из App_Start, но это тоже не помогает.

5- В Web.config у меня есть метод аутентификации как Forms (по умолчанию), а также я оставил строку подключения по умолчанию:

<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-TPFinal-20130121210447;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-TPFinal-20130121210447.mdf" providerName="System.Data.SqlClient" />
</connectionStrings>

И добавил это внутри тега system.web:

<roleManager enabled="true" cacheRolesInCookie="true" />

6- Затем, чтобы проверить, все ли работает, я использую аннотацию [Authorize(Roles = "Admins")] поверх метода About() в HomeController. Если бы все работало так, как ожидалось, это должно заставить меня войти в систему как admin/123456, чтобы увидеть страницу «О программе», контролируемую HomeController/About.

7- Я не добавлял миграции EF или что-то еще. Все остальное по умолчанию, так как VS2012 создал его автоматически. Итак, я запускаю свое приложение и нажимаю ссылку «О программе», и мне предоставляется форма входа в систему (это означает, что аннотация [Authorize (Roles = «Admins»)] делает то, что ожидается). Я пытаюсь войти в систему как admin/123456, но страница входа перезагружается снова и снова, каждый раз, когда я нажимаю кнопку входа.

Несколько вещей, которые я заметил:

-если я добавлю точку останова в методе Seed, кажется, что он не вызывается.

-когда я использую DropCreateDatabaseAlways и снова запускаю приложение, я могу войти в систему как admin/123456, что заставляет меня снова подумать, что весь мой класс DataContextDbInitializer даже не используется, поскольку я предполагаю, что БД должна быть создана с нуля, который удалит пользователя-администратора.

Я не знаю, что еще почитать, что еще попробовать... Я новичок в asp.net (надо ли это говорить?) и просто схожу с ума. Спасибо!!


person Floella    schedule 27.01.2013    source источник


Ответы (3)


Наконец-то мне удалось заставить все это работать!

Мой начальный метод теперь выглядит так:

WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);

if (!Roles.RoleExists("Admins"))
{
    Roles.CreateRole("Admins");
}
if (!WebSecurity.UserExists("admin"))
{
    WebSecurity.CreateUserAndAccount("admin", "123456");
}
if (!Roles.GetRolesForUser("admin").Contains("Admins"))
{
    Roles.AddUsersToRoles(new[] { "admin" }, new[] { "Admins" });
}
base.Seed(context);

Мой App_Start в Global.asax выглядит так:

Database.SetInitializer(new DataContextDbInitializer());
DataContext c = new DataContext();
c.Database.Initialize(true);

Я не уверен, что это на самом деле что-то делает, но у меня есть это внутри тега system.web в Web.config:

<roleManager enabled="true" cacheRolesInCookie="true" />

Я также удалил [InitializeSimpleMembership] из AccountController и класс UsersContext в AccountModels. Я переместил этот бит в свой собственный класс контекста:

public DbSet<UserProfile> UserProfiles { get; set; }

Затем, чтобы проверить, все ли работает, я использую аннотацию [Authorize(Roles = "Admins")] поверх метода About() в HomeController. Если все работает так, как ожидалось, это должно заставить меня войти в систему как admin/123456, чтобы увидеть страницу «О программе», контролируемую HomeController/About. Что делает ;)

Спасибо за помощь! Это помогло мне лучше понять, что происходит.

person Floella    schedule 28.01.2013

В MVC4 интернет-приложение по умолчанию имеет встроенную аутентификацию. Класс с именем InitializeSimpleMembershipAttribute находится в каталоге Filters. Как следует из названия, этот класс инициализирует простую базу данных членов. Если вы посмотрите на конструктор, вы увидите следующую строку:

 WebSecurity.InitializeDatabaseConnection("UserContext", "UserProfile", "UserId", "UserName", autoCreateTables: true);

Ниже этой строки вы можете вставить следующий код, чтобы создать пользователя по умолчанию:

// Create admin user.
                    if (!WebSecurity.UserExists("admin"))
                    {
                        WebSecurity.CreateUserAndAccount("admin", "12345678!");
                    }

Просто еще один способ сделать что-то.

person Dennis Bottjer    schedule 23.05.2013

Попробуйте так:

public class DataContextDbInitializer : DropCreateDatabaseAlways<DataContext>
{
    protected override void Seed(DataContext context)
    {
        if (!Roles.RoleExists("Admins"))
        {
            Roles.CreateRole("Admins");
        }
        if (!WebSecurity.UserExists("admin"))
        {
            WebSecurity.CreateUserAndAccount("admin", "123456");
        }
        if (!Roles.GetRolesForUser("admin").Contains("Admins"))
        {
            Roles.AddUsersToRoles(new[] { "admin" }, new[] { "Admins" });
        }
    }
}

и в вашем Application_Start:

Database.SetInitializer<DataContext>(new DataContextDbInitializer());
using (var ctx = new DataContext())
{
    ctx.Database.Initialize(true);
}
WebSecurity.InitializeDatabaseConnection(
    "DefaultConnection", 
    "UserProfile", 
    "UserId", 
    "UserName", 
    autoCreateTables: true
);
person Darin Dimitrov    schedule 27.01.2013
comment
Спасибо :) Я сделал, как вы сказали, и теперь я получаю исключение (по крайней мере, это что-то!), Когда я запускаю приложение и перед тем, как оно отображает домашнюю страницу: System.Web.HttpException. При установлении соединения с SQL Server произошла ошибка, связанная с сетью или конкретным экземпляром. Сервер не найден или не был доступен. Убедитесь, что имя экземпляра указано правильно и что SQL Server настроен на разрешение удаленных подключений. (поставщик: Сетевые интерфейсы SQL, ошибка: 26 - Ошибка определения местоположения сервера/экземпляра) Я не менял никаких конфигураций SQLServer и оставил соединение по умолчанию - person Floella; 27.01.2013
comment
Хорошо, небольшое обновление: я попытался использовать WebSecurity.InitializeDatabaseConnection в качестве первого вызова в App_Start, за которым следует Database.SetInitializer, а затем остальная часть кода по умолчанию. Дело в том, что если я использую DropCreateDatabaseAlways, то я получаю сообщение об ошибке Не могу удалить базу данных aspnet-TPFinal-20130121210447, потому что она в настоящее время используется (я даже перезагрузил компьютер, и я все еще получаю это!). Если я переключусь на DropCreateDatabaseIfModelChanges, то поведение будет таким же, как и в начале: я пытаюсь получить доступ к «О программе» и получаю цикл на странице входа в систему. - person Floella; 27.01.2013