Как добавить пользователей и роли в SQL для SQLMembershipProvider? - PullRequest
5 голосов
/ 17 декабря 2010

Мы мигрируем в производственную среду, и я хочу написать сценарий, чтобы администратор БД мог создать пользователя с ролями сразу после запуска сценария, сгенерированного с помощью aspnet_regsql. В среде разработки я добавлял пользователей и роли с помощью API провайдера членства в Global.asax.cs. Но я хочу избежать этого жестко закодированного подхода. Теперь у меня нет опыта работы с T-SQL. Я написал следующий скрипт, который работает, если я не запускаю его все сразу.

Use MyApps_Prod;
GO

DECLARE @user_identity CHAR(40);
DECLARE @scalar_userid AS NVARCHAR(255);
DECLARE @scalar_roleid AS NVARCHAR(255);
DECLARE @app_id AS NVARCHAR(255);
SET @user_identity = N'AMERICAS\First.Last';

SET @app_id = (SELECT DISTINCT ApplicationId 
            FROM [dbo].[aspnet_Applications] 
            WHERE loweredapplicationname = 'MyApplication');
SELECT * FROM [dbo].[aspnet_Users] WHERE UserName = @user_identity

IF NOT EXISTS (SELECT * FROM [dbo].[aspnet_Users] WHERE UserName = @user_identity ) 
BEGIN
    INSERT INTO [dbo].aspnet_Users
             ( [ApplicationId], [UserName], [LoweredUserName], [LastActivityDate] )
    VALUES
        ( @app_id, @user_identity, LOWER(@user_identity), GETDATE());
END;

DECLARE @role_name CHAR(40);
SET @role_name = N'Communicator';
IF NOT EXISTS (SELECT * FROM [dbo].[aspnet_Roles] WHERE RoleName = @role_name ) 
BEGIN
    INSERT INTO [dbo].[aspnet_Roles]
        ( [ApplicationId], [RoleName], [LoweredRoleName])
    VALUES
        (@app_id, @role_name, LOWER(@role_name))
END;


SET @scalar_userid = (SELECT DISTINCT UserID FROM [dbo].aspnet_Users WHERE UserName = @user_identity);
SET @scalar_roleid = (SELECT DISTINCT RoleID FROM [dbo].aspnet_Roles WHERE RoleName = @role_name);

INSERT INTO [dbo].aspnet_UsersInRoles (UserID, RoleID)
    VALUES (
        @scalar_userid ,
        @scalar_roleid
    );


SET @role_name = N'AccessAdministrator';
IF NOT EXISTS (SELECT * FROM [dbo].[aspnet_Roles] WHERE RoleName = @role_name ) 
BEGIN
    INSERT INTO [dbo].[aspnet_Roles]
        ( [ApplicationId], [RoleName], [LoweredRoleName])
    VALUES
        (@app_id, @role_name, LOWER(@role_name))
END;


SET @scalar_roleid = (SELECT DISTINCT RoleID FROM [dbo].aspnet_Roles WHERE RoleName = @role_name);

INSERT INTO [dbo].aspnet_UsersInRoles (UserID, RoleID)
    VALUES (
        @scalar_userid ,
        @scalar_roleid
    );
GO

Я обнаружил, что могу заставить INSERTs работать, если я заканчиваю каждый INSERT точкой с запятой, а затем добавляю GO, но затем мне нужно переопределить и переназначить каждую переменную.

Как бы настоящий разработчик SQL сделал это?

Ответы [ 4 ]

10 голосов
/ 19 декабря 2010

Вместо того чтобы писать операторы INSERT вручную, используйте хранимые процедуры, которые являются частью поставщика реализации SqlMembershipProvider и включены при установке служб приложений с помощью инструмента aspnet_reg.exe.

В частности, используйте:

  • aspnet_Roles_CreateRole для создания новой роли
  • aspnet_Membership_CreateUser для создания пользователя и предоставления его данных о членстве (пароль, секретный вопрос и ответ и т. Д.)
  • aspnet_UsersInRoles_AddUsersToRoles для добавления существующего пользователя к существующей роли

aspnet_Membership_CreateUser - единственный хитрый из всех.Предполагая, что вы храните свои пароли не в виде обычного текста, вам нужно передать либо хешированную, либо зашифрованную версию в sproc через параметр @Password.Я предлагаю использовать Reflector для проверки кода в методе SqlMembershipProvider класса CreateUser .Там вы увидите, как .NET обрабатывает эту логику под крышками.

В качестве альтернативы написанию этого сценария рассмотрите возможность написания программы командной строки, которая, возможно, читает текстовый файл и создает указанные роли, а также ассоциации пользователей и ролей пользователей.Эта программа командной строки будет напрямую использовать членский API и, следовательно, обрабатывать все детали низкого уровня.Затем вы можете выполнить эту программу командной строки как часть процесса сборки или развертывания.

Счастливого программирования!

2 голосов
/ 17 декабря 2010

Вы пытались запустить жестко запрограммированную реализацию с запущенным SQL Profiler? Это должно показать вам точный порядок запуска вещей.

0 голосов
/ 19 декабря 2010

Это не очень хорошая идея - создавать его с помощью скрипта. Также я не уверен, когда вы говорите, что вам нужно создавать вручную, если вы используете API. Вы пытались перенести существующие данные?

Но если это выбор, я бы предложил вам использовать Reflector Tool, чтобы увидеть код этих методов членства / ролей. Простого запуска хранимого процесса недостаточно, потому что может потребоваться шифрование / хеширование, выбор правильного applicationName и несколько других проверок, связанных с настройкой в ​​web.config, перед тем как хранимый процесс будет выполнен этими методами API.

Поэтому убедитесь, что вы учитываете все это, потому что вы сможете вставить данные пользователя, но когда вы захотите использовать его, вы будете использовать API, и это может сломать что-то еще.

0 голосов
/ 17 декабря 2010

«Как бы настоящий разработчик SQL сделал это?»

Вот начало. Хотя T-SQL напрямую не поддерживает массивы, я обычно перебираю переменные таблиц, рассматривая их как массивы, для сжатия / повторного использования кода. В твоем примере это не огромное преимущество. Но если бы было 10 ролей, это было бы.

Пример:


DECLARE @roles TABLE (rolename CHAR(40));
INSERT @roles
 SELECT 'Communicator'
 UNION ALL
 SELECT 'AccessAdministrator';
DECLARE @rolename CHAR(40);

--loop through the @roles table variable like it's an array
WHILE (SELECT COUNT(*) FROM @roles) > 0
  BEGIN
    SELECT TOP 1 @rolename = rolename FROM @roles;
    --Do something with the current rolename
    SELECT @rolename;
    DELETE @roles WHERE rolename = @rolename;
  END
...