如何通过Entity Framework启用SQL应用程序角色

4

我正在使用Entity Framework开发大型政府应用程序。一开始我遇到了一个关于启用SQL应用角色的问题。使用ADO.NET,我使用以下代码:

SqlCommand cmd = new SqlCommand("sys.sp_setapprole");
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Connection = _sqlConn;
            SqlParameter paramAppRoleName = new SqlParameter();
            paramAppRoleName.Direction = ParameterDirection.Input;
            paramAppRoleName.ParameterName = "@rolename";
            paramAppRoleName.Value = "AppRole";
            cmd.Parameters.Add(paramAppRoleName);

            SqlParameter paramAppRolePwd = new SqlParameter();
            paramAppRolePwd.Direction = ParameterDirection.Input;
            paramAppRolePwd.ParameterName = "@password";
            paramAppRolePwd.Value = "123456";
            cmd.Parameters.Add(paramAppRolePwd);

            SqlParameter paramCreateCookie = new SqlParameter();
            paramCreateCookie.Direction = ParameterDirection.Input;
            paramCreateCookie.ParameterName = "@fCreateCookie";
            paramCreateCookie.DbType = DbType.Boolean;
            paramCreateCookie.Value = 1;
            cmd.Parameters.Add(paramCreateCookie);

            SqlParameter paramEncrypt = new SqlParameter();
            paramEncrypt.Direction = ParameterDirection.Input;
            paramEncrypt.ParameterName = "@encrypt";
            paramEncrypt.Value = "none";
            cmd.Parameters.Add(paramEncrypt);

            SqlParameter paramEnableCookie = new SqlParameter();
            paramEnableCookie.ParameterName = "@cookie";
            paramEnableCookie.DbType = DbType.Binary;
            paramEnableCookie.Direction = ParameterDirection.Output;
            paramEnableCookie.Size = 1000;
            cmd.Parameters.Add(paramEnableCookie);

            try
            {
                cmd.ExecuteNonQuery();
                SqlParameter outVal = cmd.Parameters["@cookie"];
                // Store the enabled cookie so that approle  can be disabled with the cookie.
                _appRoleEnableCookie = (byte[]) outVal.Value;

            }
            catch (Exception ex)
            {
                result = false;
                msg = "Could not execute enable approle proc." + Environment.NewLine + ex.Message;
            }

但无论我怎么搜索,都找不到在EF上实现的方法。

另一个问题是:如何将应用程序角色添加到实体数据模型设计器中?


我正在使用以下代码执行EF参数:

AEntities ar = new AEntities();

            DbConnection con = ar.Connection;
            con.Open();
            msg = "";
            bool result = true;
            DbCommand cmd = con.CreateCommand();

            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Connection = con;
            var d = new DbParameter[]{
            new SqlParameter{ ParameterName="@r", Value ="AppRole",Direction =  ParameterDirection.Input}
          , new SqlParameter{ ParameterName="@p", Value ="123456",Direction =  ParameterDirection.Input}
           };
            string sql = "EXEC " + procName + " @rolename=@r,@password=@p";
            var s = ar.ExecuteStoreCommand(sql, d);

当运行ExecuteStoreCommand时,该行会返回错误:

应用程序角色只能在临时级别激活。


你尝试过使用ObjectContex.ExecuteStoreCommand()吗?你需要传递一个字符串,例如'EXEC sys.sp_setapprole @rolename, @password, @fCreateCookie, ...',并传递SqlParameters以提供命令中参数占位符的值。 - Pawel
2个回答

1
我会以下方式进行操作(假设使用数据库优先):
  1. I create the DbContext from the db and call it MyEntitiesBase
  2. I inherit from MyEntitiesBase to create MyEntities with the following code:

    public partial class MyEntities : MyEntitiesBase
    {
    
    private byte[] appRoleCookie;
    
    private void SetAppRole()
    {
        try
        {
            appRoleCookie = Database.SqlQuery<byte[]>(
                @"
                DECLARE @cookie VARBINARY(8000)
                DECLARE @r INT
                EXEC sp_setapprole 'user', 'pass', @fCreateCookie = true, @cookie = @cookie OUTPUT
                SELECT @cookie").First();
        }
        catch
        {
            throw new AuthenticationException();
        }
    }
    
    private void UnSetAppRole()
    {
        bool failed = Database.SqlQuery<bool>("DECLARE @result BIT; EXEC @result = sp_unsetapprole @cookie = " + appRoleCookie.ToHexadecimalString() + "; SELECT @result").First();
        if (failed)
            throw new SecurityException();
    }
    
    public MyEntities() : base()
    {
        Database.Connection.Open();
        SetAppRole();
    }
    
    private bool disposed = false;
    
    protected override void Dispose(bool disposing)
    {
        if (disposed)
            return;
        UnSetAppRole();
        Database.Connection.Close();
        disposed = true;
        base.Dispose(disposing);
    }
    }
    

ToHexadecimalString 是一个扩展方法,适用于 IEnumerable<byte>,如下所示:

public static class BytesExtensions
{
    public static string ToHexadecimalString(this IEnumerable<byte> bytes)
    {
        return "0x" + string.Concat(bytes.Select(b => b.ToString("X2")));
    }
}

就是这样。在连接池开启的情况下,一切都能正常工作。您只需使用这个继承版本,而不是由EF生成的版本。


2
我刚刚在EF6中使用IDbConnectionInterceptor实现了这段代码,效果非常好。在“Opened”方法中调用“SetAppRole”,在“Closing”方法中调用“UnSetAppRole”。谢谢。 - Duncan Howe

0

基本上你正在调用存储过程。

实体框架具有执行存储过程的功能。这里附带一个视频解释:http://msdn.microsoft.com/en-us/data/gg699321.aspx

如果您向下滚动到“使用导入函数映射存储过程”部分,您将找到与您相关的部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接