Использование NHibernate с ролями приложений SQL Server - PullRequest
2 голосов
/ 14 декабря 2011

Я использую NHibernate (свободно) для взаимодействия с базой данных, которая закрыта для всех, кроме роли приложения.

Я могу использовать роль приложения в SQL Server Management Studio с использованием сохраненных процедур: sp_setapprole и sp_unsetapprole напрямую, но я сталкиваюсь с проблемами при попытке сделать это с NHibernate:

using (var session = SessionFactory.OpenSession())
{
    byte[] cookie;

    // 1) Set the application role
    using (var command = session.Connection.CreateCommand())
    {
        command.CommandType = CommandType.StoredProcedure;
        command.CommandText = "sp_setapprole";
        command.Parameters.Add(new SqlParameter("@rolename", RoleName));
        command.Parameters.Add(new SqlParameter("@password", RolePassword));
        command.Parameters.Add(new SqlParameter("@fCreateCookie", true));
        command.Parameters.Add(
            new SqlParameter
                {
                    ParameterName = "@cookie",
                    DbType = DbType.Binary,
                    Direction = ParameterDirection.Output,
                    Size = 8000
                });

        // This works perfectly fine
        command.ExecuteNonQuery();
        var outVal = (SqlParameter)command.Parameters["@cookie"];

        // This returns a byte array value for the cookie generated
        cookie = (byte[])outVal.Value;
    }

    // 2) This line dutifully retreives my contrived Person object but renders
    //    part 3) of this saga next to useless because it performs a logout
    //    (identified with SQL Profiler) and the app role/cookie is forgotten.
    session.CreateCriteria(typeof(Person)).List<Person>().FirstOrDefault();

    // 3) Unset the application role
    using (var command = session.Connection.CreateCommand())
    {
        command.CommandType = CommandType.StoredProcedure;
        command.CommandText = "sp_unsetapprole";
        command.Parameters.Add(new SqlParameter("@cookie", cookie));
        command.ExecuteNonQuery();
    }
}

Итак, подведем итог, делая что-нибудь между 1) и 3) в приведенном выше примере вызывает сбой приложения.Двумя разными способами, в зависимости от того, пул я или нет:

Пул - Произошла серьезная ошибка в текущей команде.Результаты, если таковые имеются, должны быть отброшены.

Не объединение в пул - Невозможно сбросить роль приложения, поскольку ни одна из них не была установлена ​​или файл cookie недействителен.

Я не уверен, поможет ли это, но я подключаюсь к следующему (обычно это делается немного по-другому, но мне нужно настроить атрибут Pooling):

private static ISessionFactory CreateSessionFactory()
{
    return Fluently.Configure().Database(
        MsSqlConfiguration.MsSql2008.ConnectionString(
            "Data Source=(local);" +
            "Initial Catalog=PeopleDB;" +
            "Integrated Security=False;" +
            "User ID=someuserid;" +
            "Password=somepassword" +
            "Pooling=False"))
        .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Program>())
        .BuildSessionFactory();
}

К вашему сведениюпользователь, подключающийся в приведенном выше коде, не имеет абсолютно никаких прав доступа к базе данных, что, по крайней мере, доказывает, что sp_setapprole работает.

Кто-нибудь сталкивался с этим и смог решить его?У меня был хороший гугл, но ничего не оказалось.

Заранее спасибо, Роб

1 Ответ

2 голосов
/ 14 декабря 2011

NH создает и закрывает соединения, когда они им нужны, используя IConnectionProvider. Если каждое используемое соединение в приложении использует одну и ту же процедуру аутентификации, лучше всего реализовать собственный IConnectionProvider и настроить его на MsSqlConfiguration.MsSql2008.Provider<YourOwnConnectionProvider>();

class MyConnectionProvider : DriverConnectionProvider
{
    public override IDbConnection GetConnection()
    {
        var connection = base.GetConnection();

        byte[] cooky;
        // TODO: authenticate

        return new MyConnectionWrapper(connection, cooky);
    }

    public override void CloseConnection(IDbConnection conn)
    {
        var myConn = conn as MyConnectionWrapper;
        if (myConn != null)
        {
            // TODO: deregister with myConn.Cooky;
        }
        base.CloseConnection(conn);
    }
}
...